本文梳理了C语言中条件判断(if-else)、多分支选择(switch)以及循环结构(for、while、do-while)的核心语法、典型应用和常见陷阱,适合作为复习资料或技术存档。
一、条件判断:if-else 结构
1.1 基本语法
if (条件表达式) {
// 条件为真(非0)时执行
} else {
// 条件为假(0)时执行
}
- 条件表达式可以是任何能产生整型值的表达式,0 表示假,非 0 表示真。
- 如果代码块只有一条语句,大括号 {} 可以省略,但为可读性和避免“悬挂 else”问题,始终建议保留大括号。
1.2 多分支结构:if - else if - else
if (条件1) {
// ...
} else if (条件2) {
// ...
} else {
// 以上条件均不成立时执行
}
- 程序从上到下依次判断条件,一旦某个条件成立,执行对应代码块后直接跳出整个 if-else 链,不再继续判断后续条件。
- else 分支是可选的,但常用来捕获所有未匹配的情况(可作为“兜底”分支)。
1.3 关键示例与易错点
示例1:逻辑运算符优先级(电影选择问题)
判断条件:若两人同一排(row 相同),且座位号相邻(差值为 1 或 -1),则“开心看电影”,否则“玩手机”。
int rowA = 10, rowB = 10;
int numberA = 5, numberB = 6;
// 错误写法(优先级陷阱)
if (rowA == rowB && numberA - numberB == 1 || numberA - numberB == -1) {
printf("我会很开心的看电影");
} else {
printf("我会高兴的玩手机");
}
- 由于 && 优先级高于 ||,错误写法会被解析为:
(rowA == rowB && numberA - numberB == 1) || (numberA - numberB == -1)这导致当差值等于 -1 时,即使 rowA 不等于 rowB 也会进入 if 分支,逻辑完全错误。 - 正确做法:用括号明确组合关系。
if (rowA == rowB && (numberA - numberB == 1 || numberA - numberB == -1)) {
printf("我会很开心的看电影");
} else {
printf("我会高兴的玩手机");
}
要点:在混合使用 && 和 || 时,务必加括号清晰表达逻辑意图,不要依赖默认优先级。
示例2:多区间判断与边界处理(VIP等级)
根据充值金额划分 VIP 等级,区间应当连续、无重叠,并且要正确处理非法值(如负数)。
int amount;
printf("请输入你要充值的金额:");
scanf("%d", &amount);
if (amount >= 1 && amount <= 99) {
printf("尊贵的VIP1");
} else if (amount >= 100 && amount <= 499) {
printf("尊贵的VIP2");
} else if (amount >= 500 && amount <= 999) {
printf("尊贵的VIP3");
} else if (amount >= 1000 && amount <= 1999) {
printf("尊贵的VIP4");
} else if (amount >= 2000 && amount <= 5000) {
printf("尊贵的VIP5");
} else if (amount <= 0) {
printf("豹子头零充");
} else {
printf("顶级VIP");
}
必须注意的细节:
- >= 和 <= 的书写顺序:=> 是非法运算符,必须写成 >=
- 区间务必连续且互斥,例如第一个区间 1~99,第二个从 100 开始,避免遗漏或重叠。
- 先判断正常区间,最后用 else if 或 else 捕获异常值(如 ≤0 或 >5000),使程序对所有输入都有明确反馈。
二、多分支选择:switch 语句
2.1 适用场景
- 离散等值判断:分支条件是几个有限的、具体的整数值或字符,而非范围或复杂表达式。
- 分支数较多(如 5 个以上)时,switch 可能比多层 if-else 结构更清晰;部分编译器会为密集的 case 生成跳转表,提高执行效率。
- 若判断条件涉及区间、逻辑组合,则必须使用 if-else。
2.2 语法格式与要求
switch (整型表达式) {
case 整型常量1:
// 语句
break;
case 整型常量2:
// 语句
break;
...
default:
// 所有 case 都不匹配时执行
break;
}
- switch 后的表达式结果必须是整数类型(包括 char),不能是浮点数或字符串。
- case 后面必须跟整型常量表达式(如 1、'a'),不能是变量。
- default 分支可以放在任意位置(甚至可以省略),但习惯上放在最后。
2.3 case 穿透现象
如果某个 case 后没有 break,程序不会自动跳出 switch,而是继续执行下一个 case 中的代码,直到遇到 break 或整个 switch 结束。这一特性可有意用于多个 case 共享同一段逻辑。
int week = 3;
switch (week) {
case 1:
case 2:
case 3:
case 4:
case 5:
printf("工作日\n");
break;
case 6:
case 7:
printf("周末\n");
break;
default:
printf("无效星期\n");
break;
}
- 当 week 为 1~5 时,都会执行 printf("工作日") 并跳出。
- 若误删某个 break(例如 case 5 后面没有 break),就会发生预期外的穿透,导致逻辑错误。因此穿透应当是有意为之,且应加注释说明。
2.4 典型应用示例
基础用法:减肥计划菜单
int option;
printf("请输入你的减肥计划编号:");
scanf("%d", &option);
switch (option) {
case 1: printf("跑步"); break;
case 2: printf("游泳"); break;
case 3: printf("漫步"); break;
case 4: printf("动感单车"); break;
case 5: printf("拳击"); break;
case 6: printf("打太极"); break;
case 7: printf("好好吃一顿"); break;
default: printf("输入数据错误"); break;
}
利用穿透合并分支:电话服务菜单
int choice;
printf("请输入数字选择服务:");
scanf("%d", &choice);
switch (choice) {
case 1: printf("机票查询"); break;
case 2: printf("机票预定"); break;
case 3: printf("机票改签"); break;
case 4:
default: printf("退出服务"); break;
}
- 此处 case 4 后没有 break,直接贯穿到 default,因此输入 4 或其他未定义选项都会输出“退出服务”。
- 这种设计常用于“多种情况执行相同操作”或“将非法输入合并到默认出口”。
三、循环结构
3.1 for 循环
语法格式:
for (初始化; 条件表达式; 更新) {
// 循环体
}
执行顺序:
初始化(只执行一次)→ 条件判断 →(若为真)循环体 → 更新 → 条件判断 …… 直到条件为假。
典型示例
// 累加 1~5
int sum = 0;
for (int i = 1; i <= 5; i++) {
sum += i;
}
printf("%d\n", sum); // 输出 15
// 输出 1~5 再逆序输出 5~1
for (int i = 1; i <= 5; i++) printf("%d ", i);
printf("\n");
for (int i = 5; i >= 1; i--) printf("%d ", i);
printf("\n");
// 1~100 之间的偶数和
sum = 0;
for (int i = 1; i <= 100; i++) {
if (i % 2 == 0) {
sum += i;
}
}
printf("%d\n", sum); // 2550
// 输入两个数,统计区间内既能被 6 又能被 8 整除的数的个数
int a, b, count = 0;
printf("输入两个整数表示范围:");
scanf("%d %d", &a, &b);
int min = (a < b) ? a : b;
int max = (a > b) ? a : b;
for (int i = min; i <= max; i++) {
if (i % 6 == 0 && i % 8 == 0) {
count++;
}
}
printf("个数:%d\n", count);
// 注:既能被6又能被8整除即为24的倍数,可用 i % 24 == 0 简化
- 循环变量 i 定义在 for 的初始化部分(C99 起支持),其作用域仅限于循环内部。一旦程序结束内容变量i会被直接销毁
- 区间统计示例中,先用条件表达式确定 min 和 max,保证了无论输入顺序如何都能正确处理。
3.2 while 循环
语法格式:
while (条件表达式) {
// 循环体
}
- 先判断条件,条件为真才执行循环体,否则一次都不执行。
- 循环变量的更新通常放在循环体内部,需要开发者自行保证条件能最终变为假,否则会造成死循环。
示例:用 while 实现 1~5 的累加
int i = 1, sum = 0;
while (i <= 5) {
sum += i;
i++;
}
printf("%d\n", sum);
3.3 for 与 while 的对比与选择
| 比较维度 | for 循环 | while 循环 |
|---|
| 适用场景 | 循环次数确定(或可计算)时 | 循环次数不确定,依赖某个条件动态变化 |
| 结构特点 | 初始化、条件、更新集中在一行,紧凑 | 初始化在循环前,更新在循环体内,三者分散 |
| 可读性 | 计数循环一目了然 | 条件驱动的循环意图更明显 |
| 典型用例 | 遍历数组、固定次数累加、定长处理 | 等待用户输入特定值、读取文件到 EOF、游戏主循环等 |
| 相互转换 | 任何 for 都可用 while 改写 | 任何 while 也可用 for 改写 |
选择建议:
- 当循环有明确的起点、终点和步长时,优先使用 for(如 for(i=0; i<n; i++))。
- 当终止条件是某个复杂状态或外部事件时比如:需要一直读取某个文件的内容,如果你用for来实现就必须直到开始与结束的范围,那么一个文件当中这么多字节我们不可能一个一个去读吧,这是while就能体现出它的优势了:
while(1){ //条件表达式为1表示一直成立
//循环体
//在循环体内实现你读取的逻辑,此时while就会一直执行读取工作,直到结果为假才得以结束
}
3.4 do-while 循环(补充)
do {
// 循环体
} while (条件);
- 特点:无论条件真假,循环体至少执行一次。适合菜单至少显示一次、先执行再询问的场景。
- while 和 for 都是先判断后执行,do-while 是先执行后判断。
四、总结与避坑指南
- 优先级与括号:
&& 优先级高于 ||,混合使用时必须用括号明确逻辑,避免优先级误解导致隐蔽 bug。 - 区间完整性:编写 if-else if 链时,确保区间不重叠、不遗漏,并考虑非法输入的处理路径(用 else 兜底)。
- switch 的限制与穿透:表达式和 case 值仅限整数或字符;case 后必须是常量;遗漏 break 会导致穿透,除非有意利用穿透特性,否则必须补全 break。
- 循环变量的作用域:C99 起,for 内定义的变量仅循环内可见,更安全;while 的变量需提前定义,注意避免在循环外部意外访问或误用。
- 避免无限循环:for(;;) 和 while(1) 是刻意死循环,需在循环体内使用 break、return 或 exit 正确退出,切勿写出因条件永不更新而导致的意外死循环。
- 始终使用大括号:即使循环体或分支体只有一条语句,也建议用 {} 括起来,避免悬挂 else 或未来修改代码时引入错误。
- 边界条件测试:对于区间判断,务必测试边界值(如最小值、最大值、刚好超出范围的值),确保条件逻辑完全符合预期。