摘要 :分支让程序按条件选路,循环让它重复执行。本文从判断一个数的正负开始,先把关系、逻辑操作符和
if、switch讲成一条选路链,再把while、for、do-while放进同一个重复任务里比较,最后用break、continue、嵌套和goto处理循环中途的跳转,并集中列出常见错误。
文章目录
- [1. 分支:让程序选路](#1. 分支:让程序选路)
-
- [1.1 先判断一个数的正负](#1.1 先判断一个数的正负)
- [1.2 条件怎么写:关系与逻辑操作符](#1.2 条件怎么写:关系与逻辑操作符)
- [1.3 多分支:else if 与 switch](#1.3 多分支:else if 与 switch)
- [1.4 条件操作符](#1.4 条件操作符)
- [2. 循环:让程序重复](#2. 循环:让程序重复)
-
- [2.1 while:先判断再执行](#2.1 while:先判断再执行)
- [2.2 for:三部分写在一行](#2.2 for:三部分写在一行)
- [2.3 do-while:至少执行一次](#2.3 do-while:至少执行一次)
- [2.4 三种循环怎么选](#2.4 三种循环怎么选)
- [3. 循环控制:中途退出与多层跳转](#3. 循环控制:中途退出与多层跳转)
-
- [3.1 break 与 continue](#3.1 break 与 continue)
- [3.2 嵌套循环](#3.2 嵌套循环)
- [3.3 goto:一次跳出多层](#3.3 goto:一次跳出多层)
- [4. 常见错误](#4. 常见错误)
- [5. 小结](#5. 小结)
1. 分支:让程序选路
1.1 先判断一个数的正负
输入一个整数,输出它是正数、负数还是零。程序要分三种情况,用 if 的多分支写:
c
#include <stdio.h>
int main(void)
{
int n = 0;
scanf("%d", &n);
if (n > 0)
printf("正数\n");
else if (n < 0)
printf("负数\n");
else
printf("零\n");
return 0;
}
本文程序都在 VS2026 里新建 .c 文件编译。scanf 会触发 C4996,在文件第一行、任何 #include 之前加 #define _CRT_SECURE_NO_WARNINGS 1,后文代码块省略这一行。
依次输入 5、-3、0,输出:
text
正数
负数
零
if 后面的括号里是条件表达式。条件按 0 为假、非 0 为真解释,if (n) 和 if (n != 0) 等价。
else if 链从上到下判断,只执行第一个成立的分支。条件要从严格写到宽松,顺序反了,后面的分支就轮不到。
比如按分数分档,先判 score >= 90,再判 score >= 60。如果把 >= 60 放在前面,95 分也会被归进「及格」。
if 和 else 默认只控制紧随其后的一条语句。下面这段代码里,第二行 printf 不受 if 控制,score 小于 60 时也会打印:
c
if (score >= 60)
printf("及格\n");
printf("庆祝\n"); // 缩进看起来在 if 里,实际不是
要控制多条语句,用一对大括号把它们括成程序块。
else 与前面最近的、还没有配对的 if 结合,和缩进无关。看这段程序:
c
#include <stdio.h>
int main(void)
{
int a = 0;
int b = 2;
if (a == 1)
if (b == 2)
printf("hehe\n");
else
printf("haha\n");
return 0;
}
运行结果是什么也不输出。else 配给了内层 if,结构变成外层 if 包住整个内层 if...else。
外层条件是 a == 1,a 是 0,不成立,内层没有机会执行。想让 else 配外层,给内层 if 加上大括号。
这个程序只用到分支。要继续处理多个学生、多次输入,还得让程序重复;要把条件组合起来、在多个固定值里选一个,也需要更多写法。后面按四类展开:
| 要做的事 | 语法 |
|---|---|
| 按条件选一条路 | if / else if / switch / ?: |
| 让一段代码重复 | while / for / do-while |
| 中途退出或跳过 | break / continue |
| 一次跳出多层 | goto |
先补条件本身的写法,再看多分支。
1.2 条件怎么写:关系与逻辑操作符
1.1 的 n > 0 用到了 >。关系操作符比较两个值,结果是 int 类型的 0 或 1:
| 操作符 | 含义 | 例子 | 结果 |
|---|---|---|---|
> |
大于 | 20 > 12 |
1 |
>= |
大于或等于 | 12 >= 12 |
1 |
< |
小于 | 12 < 20 |
1 |
<= |
小于或等于 | 20 <= 12 |
0 |
== |
等于 | 12 == 20 |
0 |
!= |
不等于 | 12 != 20 |
1 |
== 和 = 只差一个字符,作用完全不同。if (x = 3) 先把 3 赋给 x,表达式的值也是 3,条件恒真。
把常量写在左边 if (3 == x),误写成 = 时编译器会直接报错,因为 3 不能被赋值。
关系操作符也不能连写。18 <= age <= 36 先算 18 <= age 得到 0 或 1,再拿结果和 36 比,条件恒真:
c
#include <stdio.h>
int main(void)
{
int age = 0;
scanf("%d", &age);
if (18 <= age <= 36)
printf("青年\n");
return 0;
}
输入 10 也会打印「青年」。正确写法是两个比较用 && 连接:age >= 18 && age <= 36。
逻辑操作符把多个条件组合起来:
| 左操作数 | 右操作数 | && | || |
|------|------|------|------|
| 0 | 0 | 0 | 0 |
| 0 | 非 0 | 0 | 1 |
| 非 0 | 0 | 0 | 1 |
| 非 0 | 非 0 | 1 | 1 |
&& 和 || 从左向右求值,并且保证短路:&& 左边为 0 时,右边不再算;|| 左边非 0 时,右边不再算。
c
#include <stdio.h>
int main(void)
{
int a = 0;
int b = 2;
int d = 4;
int i = a++ && ++b && d++;
printf("i=%d a=%d b=%d d=%d\n", i, a, b, d);
return 0;
}
输出:
text
i=0 a=1 b=2 d=4
a++ 先取 0 参与判断,再把 a 加到 1。左边已经是 0,&& 直接短路,++b 和 d++ 都没有执行,i 得到 0。
把自增、赋值这类有副作用的操作写进条件,结果就依赖求值顺序,读代码时容易看错。条件里尽量只做比较,避免副作用。
闰年的规则是:能被 4 整除且不能被 100 整除,或者能被 400 整除。用逻辑操作符写成一个条件:
c
#include <stdio.h>
int main(void)
{
int year = 0;
scanf("%d", &year);
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
printf("%d 是闰年\n", year);
else
printf("%d 不是闰年\n", year);
return 0;
}
输入 2024、1900、2000,依次输出:
text
2024 是闰年
1900 不是闰年
2000 是闰年
&& 的优先级高于 ||,括号把两组条件分开,读起来也更清楚。
1.3 多分支:else if 与 switch
1.1 的分档用 else if 能写。如果判断的是「一个整型值等于若干固定常量中的哪一个」,switch 更直接。输入 1~7,判断工作日还是周末:
c
#include <stdio.h>
int main(void)
{
int day = 0;
scanf("%d", &day);
switch (day)
{
case 1:
case 2:
case 3:
case 4:
case 5:
printf("工作日\n");
break;
case 6:
case 7:
printf("周末\n");
break;
default:
printf("输入错误\n");
break;
}
return 0;
}
输入 3 输出「工作日」,输入 6 输出「周末」,输入 9 走 default 输出「输入错误」。
case 1: 到 case 5: 后面没有语句,它们只是入口标签。匹配到其中任意一个,都会继续往下执行同一个 printf,直到遇到 break。
如果某个 case 末尾漏了 break,执行会继续进入下一个 case,这叫贯穿。下面这段输入 5 会连续打印两行:
c
case 5:
printf("工作日\n");
case 6:
printf("周末\n");
break;
有时会故意利用贯穿,让多个值共用一段代码;但每个分支结束时该不该写 break,要明确。
switch 后的表达式必须是整型,case 后必须是整型常量表达式。范围判断、浮点数和字符串比较都只能交给 if:
| 场景 | 选择 |
|---|---|
| 一个整型值等于若干固定常量之一 | switch |
范围判断,如 score >= 60 && score < 70 |
if |
| 浮点数或字符串比较 | if |
default 的位置不限,通常放在最后;它后面漏了 break,同样会继续往下执行。
1.4 条件操作符
只根据一个条件在两个值里选一个,if...else 要写四行;条件操作符一行就够:
c
exp1 ? exp2 : exp3
exp1 为真求 exp2,为假求 exp3,另一支不参与求值。
c
#include <stdio.h>
int main(void)
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
int m = a > b ? a : b;
printf("较大值:%d\n", m);
return 0;
}
输入 3 7,输出 较大值:7。它本质上是表达式,可以直接写在 printf 里;嵌套超过两层就该换回 if。
2. 循环:让程序重复
判断一次只能处理一个输入。要打印 1 到 10、处理多个学生,或者一直猜到答案,都需要让同一段代码重复执行。
2.1 while:先判断再执行
while 先判断条件,条件为真才执行循环体,执行完再回到条件:
c
#include <stdio.h>
int main(void)
{
int i = 1;
while (i <= 10)
{
printf("%d ", i);
i++;
}
printf("\n");
return 0;
}
输出 1 2 3 4 5 6 7 8 9 10。如果一开始条件就为假,循环体一次也不执行。
while (1) 是恒真条件,靠循环体里的 break 退出。普通 while 的条件写错时,也可能一直跑下去。
2.2 for:三部分写在一行
while 的初始化、判断、调整分散在三处,循环一长就容易漏掉调整。for 把三部分集中到一行:
c
#include <stdio.h>
int main(void)
{
for (int i = 1; i <= 10; i++)
printf("%d ", i);
printf("\n");
return 0;
}
输出与 while 版相同。三部分按固定顺序执行:初始化只做一次;每次先判断,条件为真执行循环体,再执行调整,然后回到判断。
计数次数明确时用 for,三个部分集中,不容易漏掉调整。C99 起可以在初始化部分声明循环变量,i 只在循环内可见。
2.3 do-while:至少执行一次
输入一个整数,统计它是几位数。0 也是一位数,循环体必须先执行一次再判断。do-while 正好是先执行、后判断:
c
#include <stdio.h>
int main(void)
{
int n = 0;
scanf("%d", &n);
int count = 0;
do
{
count++;
n /= 10;
} while (n != 0);
printf("%d 位数\n", count);
return 0;
}
输入 1234 输出 4 位数,输入 0 输出 1 位数。如果改成 while (n > 0),输入 0 时一次都不循环,位数会算成 0。
2.4 三种循环怎么选

三种循环的区别集中在判断位置:
| 循环 | 判断时机 | 最少执行次数 | 适合 |
|---|---|---|---|
while |
循环体之前 | 0 | 次数未知,先看条件 |
for |
循环体之前 | 0 | 次数已知或可计算 |
do-while |
循环体之后 | 1 | 至少执行一次,如菜单、输入校验 |
for (;;) 与 while (1) 等价,都是恒真条件。
3. 循环控制:中途退出与多层跳转
循环不总是从头跑到尾:找到答案要提前结束,跳过某个值要继续下一轮,内层循环结束时外层可能也要停。
3.1 break 与 continue
break 立即结束它所在的那一层循环;continue 跳过本次循环剩下的语句,进入下一次。
for 里的 continue 跳到调整部分,i++ 仍会执行:
c
#include <stdio.h>
int main(void)
{
for (int i = 1; i <= 10; i++)
{
if (i == 5)
continue;
printf("%d ", i);
}
printf("\n");
return 0;
}
输出 1 2 3 4 6 7 8 9 10,5 被跳过,循环继续。把 continue 换成 break,输出到 4 就停。
while 里的 continue 跳到条件判断。调整语句如果写在 continue 后面,就会被跳过:
c
#include <stdio.h>
int main(void)
{
int i = 1;
while (i <= 10)
{
if (i == 5)
continue;
printf("%d ", i);
i++;
}
return 0;
}
输出 1 2 3 4 后,i 停在 5,条件一直成立,程序卡住。运行这段代码需要手动停止。
要避免这种写法:把 i++ 放到 continue 之前,或者直接用 for。

| 循环 | break |
continue 跳转 |
|---|---|---|
while |
结束整个循环 | 条件判断 |
for |
结束整个循环 | 调整表达式 |
do-while |
结束整个循环 | 末尾的条件判断 |
两种跳转都只作用于最近的一层循环。
3.2 嵌套循环
判断 100~200 之间的素数需要两层循环:外层逐个取数,内层试除。
素数是只能被 1 和自身整除的大于 1 的整数。对每个 i,用 2 到 i-1 的数去试除;只要有一个能整除,i 就不是素数。
c
#include <stdio.h>
int main(void)
{
int count = 0;
for (int i = 100; i <= 200; i++)
{
int is_prime = 1;
for (int j = 2; j * j <= i; j++)
{
if (i % j == 0)
{
is_prime = 0;
break;
}
}
if (is_prime)
{
printf("%d ", i);
count++;
}
}
printf("\n共 %d 个\n", count);
return 0;
}
内层发现因子后把 is_prime 置 0 并 break,这个 break 只退出内层;外层拿到标志,继续判断下一个 i。
试除只需要到 i \sqrt{i} i :如果 i 有一个大于 i \sqrt{i} i 的因子,必然对应一个小于 i \sqrt{i} i 的因子。代码写成 j * j <= i,不用引入 sqrt。
输出:
text
101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199
共 21 个
共 21 个素数。每个 i 的试除次数从约 i 次降到约 i \sqrt{i} i 次。
3.3 goto:一次跳出多层
内层 break 只退一层。两层以上要连续 break,或者加一个标志变量让外层也停。goto 可以在同一个函数内跳到指定标号:
c
#include <stdio.h>
int main(void)
{
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (i == 1 && j == 1)
goto found;
printf("%d,%d\n", i, j);
}
}
found:
printf("跳出两层循环\n");
return 0;
}
输出:
text
0,0
0,1
0,2
1,0
跳出两层循环
当 i == 1 && j == 1 时,goto found 一次跳出两层循环。用 break 只能退出内层,还得在外层再加判断。
goto 也能用于统一错误处理,但跳转范围太自由,容易把流程打乱。除了从多层嵌套中退出,其他场景优先用循环条件和 break。
4. 常见错误
前面各节的错误集中在这里,写完循环和分支后可以对着查:
| 症状 | 原因 | 改法 |
|---|---|---|
if (x = 3) 条件总成立 |
把 == 写成 = |
比较用 ==;常量放左边 |
18 <= age <= 36 对 10 岁也成立 |
关系操作符连写,先算成 0/1 | 写成 age >= 18 && age <= 36 |
else 配错 if |
只看缩进,没看配对规则 | 给内层 if 加大括号 |
switch 执行了下一个分支 |
漏写 break |
每个分支末尾检查 break |
while 里 continue 后卡死 |
调整语句写在 continue 后面 |
调整放前面,或改用 for |
内层 break 后外层还在跑 |
break 只退一层 |
用标志变量或 goto |
| 循环多打印或少打印一次 | 边界写成 < 还是 <= 没核对 |
用 1~10 的小范围先验证边界 |
5. 小结
- 0 为假,非 0 为真;
if / else if / else只执行第一个成立的分支,else与最近的未配对if结合。 - 关系操作符的结果是 0 或 1,不能连写;
==不是=。 &&、||会短路,右侧可能不执行;结果只有 0 和 1。switch只做整型等值匹配;case是入口标签,漏写break会贯穿。while、for先判断,do-while至少执行一次;for的三部分最集中。break结束最近一层循环;continue在while中跳到判断,在for中跳到调整。- 嵌套循环要退多层时,用标志变量或
goto;常见错误先查第 4 节的表。