switch 语句
switch 语句是一种多路分支控制结构,它根据一个表达式的值来决定执行哪个代码块,它常用于替代多个 if-else if-else 语句,使代码更清晰、更易读。
switch 语句的基本语法如下:
switch (expression) {
case constant_expression1:
// 当 expression 的值等于 constant_expression1 时,从这里开始执行
statement(s);
break; // 可选,但强烈推荐
case constant_expression2:
// 当 expression 的值等于 constant_expression2 时,从这里开始执行
statement(s);
break; // 可选,但强烈推荐
default:
// expression 的值不匹配任何一个 case,从这里执行
statement(s);
break; // 可选
}
case 的作用
case 关键字后面跟一个常量表达式(比如一个整数、字符等),它的作用是:
case本身不执行任何操作,它更像是一个或一个入口点。- 匹配:
switch语句会将expression的值与每个case后面的constant_expression进行比较。 - 跳转:一旦找到第一个匹配的
case,程序就会跳转到那个case标签处,并开始执行其后面的代码。
break 的作用
break 关键字的作用是立即终止并退出当前的 switch 语句。
break 和 case 的协同工作:case穿透 (Case Fall-through)
这是理解 switch 语句最关键的一点。如果没有 break 语句,程序会继续执行下一个 case 的代码,而不会进行任何新的匹配。 这个特性被称为 "case穿透" 或 "fall-through"。
让我们通过例子来理解。
示例 1:有 break 的情况(标准用法)
#include <stdio.h>
int main() {
int day = 3;
switch (day) {
case 1:
printf("Monday\n");
break; // 执行完 printf 后,遇到 break,立即退出 switch
case 2:
printf("Tuesday\n");
break; // 执行完 printf 后,遇到 break,立即退出 switch
case 3:
printf("Wednesday\n");
break; // 执行完 printf 后,遇到 break,立即退出 switch
default:
printf("Unknown day\n");
break;
}
return 0;
}
输出:
Wednesday
执行流程:
day的值是3。switch进入,开始匹配case。case 1(值为1) 不匹配。case 2(值为2) 不匹配。case 3(值为3) 匹配。- 程序跳转到
case 3:的位置,执行printf("Wednesday\n");。 - 遇到
break;语句,立即终止整个switch结构。 - 程序继续执行
switch之后的代码(return 0;)。
示例 2:没有 break 的情况(case穿透)
#include <stdio.h>
int main() {
int number = 2;
switch (number) {
case 1:
printf("Option 1\n");
break;
case 2:
printf("Option 2\n");
// 注意:这里没有 break!
case 3:
printf("Option 3\n");
break;
default:
printf("Default option\n");
}
return 0;
}
输出:
Option 2
Option 3
执行流程:
number的值是2。switch进入,case 1不匹配。case 2(值为2) 匹配。- 程序跳转到
case 2:的位置,执行printf("Option 2\n");。 - 没有遇到
break,所以程序不会退出switch,它会继续向下执行。 - 它直接进入下一个
case(case 3),执行其代码printf("Option 3\n");。 - 遇到
break;,终于退出了switch。
这种“掉下去”的特性就是 case穿透。
case穿透 的实际应用
虽然 case穿透 常常是一个疏忽导致的错误,但它也可以被有意利用来实现某些逻辑。
示例 3:利用 case穿透 简化代码
假设我们要根据一个分数评定等级:90-100是A,80-89是B,70-79是C,60-69是D,60以下是F,我们可以这样写:
#include <stdio.h>
int main() {
int score = 85;
switch (score / 10) { // 85 / 10 = 8
case 10:
case 9:
printf("Grade: A\n");
break;
case 8:
printf("Grade: B\n");
break;
case 7:
printf("Grade: C\n");
break;
case 6:
printf("Grade: D\n");
break;
default: // 0, 1, 2, 3, 4, 5
printf("Grade: F\n");
break;
}
return 0;
}
输出:
Grade: B
执行流程:
score是 85,score / 10的结果是 8。switch匹配case 8:。- 执行
printf("Grade: B\n");。 - 遇到
break,退出switch。
score 是 95 呢?
score / 10的结果是 9。switch匹配case 9:。- 执行
printf("Grade: A\n");。 - 遇到
break,退出switch。
score 是 100 呢?
score / 10的结果是 10。switch匹配case 10:。- 由于没有
break,程序会穿透到下一个case(case 9:)。 - 执行
printf("Grade: A\n");。 - 遇到
break,退出switch。
这样,我们用 case穿透 巧妙地处理了两个范围(90-100)共享同一种情况(Grade A)。
default 子句
default 是 switch 的可选部分。switch 的表达式的值不匹配任何一个 case,那么程序就会跳转到 default 标签处执行。
default 的位置是灵活的,但通常放在最后。
#include <stdio.h>
int main() {
int option = 5;
switch (option) {
case 1:
printf("You selected 1.\n");
break;
case 2:
printf("You selected 2.\n");
break;
default: // option 的值是 5,不匹配 case 1 或 2,所以执行这里
printf("Invalid option.\n");
break;
}
return 0;
}
输出:
Invalid option.
总结与最佳实践
case是入口,不是出口:case只是告诉程序从哪里开始执行。break是出口:break是用来终止switch语句的。绝大多数情况下,每个case的末尾都应该有一个break。- 警惕
case穿透:忘记写break是一个非常常见的初学者错误,会导致逻辑混乱和难以发现的 bug。 - 利用
case穿透:当你发现多个case需要执行完全相同的代码块时,可以有意地省略break来利用case穿透,使代码更简洁。 default是好习惯:即使你认为所有情况都已覆盖,也最好加上一个default子句(里面可以只放一个break),用于处理意外情况,增强代码的健壮性。
记住这个核心原则:switch 找到匹配的 case 后会一路执行下去,直到遇到 break 或 switch 语句的结束大括号 。
