分支结构
前面我们学会了用变量存数据和用运算符做判断。但程序不能只“一条道走到黑”,它需要根据不同的情况走不同的路。这就是分支结构要做的事情。这篇文章我们来讲 C 语言里的分支语句。
学习目标
读完这篇文章,你会掌握:
if、if-else、if-else if-else的写法- 嵌套
if的注意事项 switch-case的用法和break的作用- 分支结构里最容易踩的几个坑
为什么需要分支
想象你在写一个成绩管理系统:
- 如果分数大于等于 90,输出“优秀”
- 如果分数在 60 到 89 之间,输出“及格”
- 否则输出“不及格”
这种“如果……就……否则……”的逻辑,靠我们前面学的顺序执行和运算是表达不了的,必须引入分支结构。
if 语句
最简单的分支是 if:如果条件成立,就执行大括号里的代码。
#include <stdio.h>
int main() {
int score = 85;
if (score >= 60) {
printf("及格了\n");
}
return 0;
}
如果 if 后面只有一行代码,大括号可以省略:
if (score >= 60)
printf("及格了\n");
但我不建议你省略。以后加代码时很容易忘记补大括号,导致逻辑错误。养成写大括号的习惯,能避免很多麻烦。
if-else 语句
if-else 表示二选一:条件成立走一个分支,不成立走另一个分支。
#include <stdio.h>
int main() {
int score = 55;
if (score >= 60) {
printf("及格了\n");
} else {
printf("不及格,补考吧\n");
}
return 0;
}
if-else if-else 语句
如果需要判断多种情况,就用 if-else if-else:
#include <stdio.h>
int main() {
int score = 85;
if (score >= 90) {
printf("优秀\n");
} else if (score >= 80) {
printf("良好\n");
} else if (score >= 60) {
printf("及格\n");
} else {
printf("不及格\n");
}
return 0;
}
执行顺序是从上到下,一旦某个条件成立,就会执行对应的代码块,然后整个分支结构结束,后面的条件不会再判断。
提示
写 if-else if 的时候,要注意条件的顺序。如果把 score >= 60 写在 score >= 90 前面,那 90 分以上的学生也会被判成“及格”。
else 的匹配规则:悬挂 else
当 if-else 嵌套时,else 总是与最近的未匹配 if 结合。初学者写嵌套时容易产生误解:
if (a > 0)
if (a > 10)
printf("a > 10\n");
else
printf("a <= 0\n"); // 这个 else 其实属于第二个 if,不是第一个!
为了帮助自己和读者理解,建议总是用大括号明确范围:
if (a > 0) {
if (a > 10) {
printf("a > 10\n");
}
} else {
printf("a <= 0\n");
}
嵌套 if
if 里面还可以再写 if,这叫嵌套分支。
#include <stdio.h>
int main() {
int score = 75;
int attendance = 85;
if (score >= 60) {
if (attendance >= 80) {
printf("成绩和出勤都达标\n");
} else {
printf("成绩达标,但出勤不够\n");
}
} else {
printf("成绩不达标\n");
}
return 0;
}
嵌套层数多了代码会变得很难读。如果发现自己写了三四层嵌套,可以考虑用更清晰的结构,或者把逻辑拆成函数。
switch-case 语句
当要判断一个变量是否等于某个固定值时,switch-case 比一堆 if-else if 更清爽。
#include <stdio.h>
int main() {
int day = 3;
switch (day) {
case 1:
printf("星期一\n");
break;
case 2:
printf("星期二\n");
break;
case 3:
printf("星期三\n");
break;
case 4:
printf("星期四\n");
break;
case 5:
printf("星期五\n");
break;
default:
printf("周末\n");
break;
}
return 0;
}
break 的作用
switch 里每个 case 后面通常都要跟 break。如果没有 break,程序会继续执行下一个 case 的代码,这种现象叫做“贯穿”。
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");
}
在这个例子里,1 到 5 都会走到同一个输出,这是“贯穿”的合理利用。但大部分时候,我们写 case 是想让它只执行一个分支,所以别忘了 break。
提示
switch 只能用于整型、字符型或枚举类型,不能用于浮点数或字符串。如果你需要判断小数范围,还是得用 if-else。
default
default 相当于 if-else 里的 else,处理所有没被列出来的情况。写上它是个好习惯,可以提高程序的健壮性。
条件表达式
上一篇我们学过的三元运算符 ?: 也可以用来做分支,适合简单的二选一。
#include <stdio.h>
int main() {
int a = 5, b = 3;
int max = (a > b) ? a : b;
printf("较大值是:%d\n", max);
return 0;
}
三元表达式写在一行里很简洁,但嵌套太多会降低可读性。一般只建议一层三元表达式。
常见错误与注意事项
- 把
==写成=
这是 C 语言里最常见的 bug 之一:
int a = 0;
if (a = 1) { // 这里是赋值,a 被改成 1,条件恒为真
printf("a 等于 1\n");
}
正确的写法:
if (a == 1) {
printf("a 等于 1\n");
}
有些程序员会故意把常量写在左边,比如 if (1 == a),这样如果漏写一个等号,1 = a 会直接编译报错。这个习惯叫“Yoda 条件”,你可以试试。
- 忘记写大括号
if (score >= 60)
printf("及格\n");
printf("奖励一朵小红花\n"); // 这一行其实不在 if 里!
switch里漏写 break
case 1:
printf("一\n");
// 漏了 break,会继续执行 case 2
case 2:
printf("二\n");
break;
- 用
switch判断范围
switch (score) {
case score >= 90: // 错误!case 后面必须是常量表达式
...
}
条件要表达业务含义,而不是凑出真假
if (temperature > 35.0) {
/* 高温处理 */
}
把复杂条件拆成有名字的布尔变量,往往比一行塞满 && 和 || 更容易检查:
bool is_adult = age >= 18;
bool has_ticket = ticket_count > 0;
if (is_adult && has_ticket) {
enter();
}
浮点数通常不直接判断相等
经过计算的浮点数可能存在舍入误差:
#include <math.h>
if (fabs(a - b) < 1e-9) {
/* 在当前问题允许误差内相等 */
}
容差不能机械固定,应该结合数值量级和业务精度。整数、枚举和明确赋值的特殊浮点值则另当别论。
switch 的控制流要显式
默认情况下,一个 case 执行完会继续进入下一个 case。需要贯穿时应注释说明;不需要时写 break。C23 和不同编译器对显式 fallthrough 标记支持不同,入门代码至少要用清楚注释。
守卫式返回减少嵌套
int process(const int *data, size_t n) {
if (data == NULL) return -1;
if (n == 0) return 0;
/* 主要逻辑不必再缩进两层 */
return 1;
}
早返回不是坏习惯;当它清楚地处理前置条件,并且没有遗漏资源释放时,通常比深层嵌套更易读。
小结
这篇文章我们讲了 C 语言的分支结构:
if:单分支if-else:二选一if-else if-else:多分支- 嵌套
if:处理更复杂的组合条件 switch-case:适合判断离散值,注意break和default- 三元表达式:简单二选一时使用
分支结构让程序有了“判断力”。但程序还需要能反复做一件事的能力,这就是我们下一篇要讲的内容:循环结构。