C语言小课堂:switch

我们今天来一起学习C语言中的 switch 语句。

  1. 什么是 switch 语句?

在C语言中, switch 语句是一种多分支选择语句,它允许程序根据一个表达式的值,从多个代码块中选择一个来执行。它提供了一种比使用多个 if-else if-else 语句更简洁、更清晰的方式来处理复杂的条件判断,特别是当你有多个可能的值需要判断时。

switch 语句的基本结构如下:

switch (expression) {
case constant_expression_1:
// 当 expression 的值等于 constant_expression_1 时执行的代码
break; // break 语句用于跳出 switch 结构
case constant_expression_2:
// 当 expression 的值等于 constant_expression_2 时执行的代码
break;
// ... 可以有任意数量的 case 分支
default:
// 当 expression 的值与所有 case 都不匹配时执行的代码(可选)
break; // 默认分支中的 break 也是可选的,因为已经是最后一个分支了
}

expression:这是一个整型表达式(可以是 int , char , enum 等类型,但不能是 float 或 double)。 switch 语句会计算这个表达式的值。

case constant_expression:case 关键字后面跟着一个 常量表达式 (必须是常量,不能是变量或范围)。当 expression 的值与某个 case 后面的 constant_expression 相等时,对应的 case 代码块就会被执行。

break 语句 : 这是 switch 语句中至关重要的一部分!break 语句用于 跳出 switch 结构 。如果没有 break,程序会继续执行下一个 case 的代码,直到遇到 break 或 switch 结束,这被称为“ 穿透”(fall-through)。

default 关键字 :这是一个可选的关键字,用于处理 expression 的值与所有 case 都不匹配的情况。如果 default 存在,并且没有 case 匹配成功,那么 default 后面的代码块就会被执行。default 可以放在 switch 块内的任何位置,但通常放在最后。

  1. 何时使用 switch 语句?

当你需要根据一个变量或表达式的特定、离散的整型值来执行不同的操作时,switch 语句是理想的选择。

什么时候用?

当你有多个选项或状态需要根据一个特定的值进行分发时。

例如,根据用户输入的菜单选项执行不同功能。

根据星期几显示不同的日程。

处理状态机的不同状态转换。

为什么用?

代码可读性更高:相比于长串的 if-else if-else 结构,switch 语句在处理多重等值判断时,逻辑结构更清晰,更易于理解和维护。

执行效率可能更高:在某些情况下,编译器可能会优化 switch 语句,使其比一系列 if-else if 链更高效,尤其是在 case 分支数量很多时。

避免“嵌套地狱”:可以有效避免多层 if-else 嵌套带来的复杂性和可读性下降。

和关联知识点的联系和区别(if-else if-else) :

如果你的判断基于一个变量的特定值,并且这些值是离散的整型或字符型,那么 switch 是更好的选择。

如果你的判断涉及范围、不等式、浮点数比较或复杂的逻辑组合,那么 if-else if-else 是唯一或更合适的选择。

if-else if-else:更通用,可以处理任何类型的条件(包括范围、逻辑组合等),灵活性更高。

switch:专门用于处理基于单个整型表达式的等值判断。它不能直接处理浮点数,也不能直接处理复杂的逻辑条件(如 x > 10 或 y == 'A' && z < 5)。

选择依据:

如果你的判断基于一个变量的特定值,并且这些值是离散的整型或字符型,那么 switch 是更好的选择。

如果你的判断涉及范围、不等式、浮点数比较或复杂的逻辑组合,那么 if-else if-else 是唯一或更合适的选择。

在编程学习中的地位和作用:

switch 语句是C语言中控制流的重要组成部分,与 if-else、循环语句( for , while)共同构成了程序的基本执行骨架。

掌握 switch 能够让你编写出更结构化、更高效、更易读的代码,是初学者必须熟练掌握的技能。

  1. 怎么使用 switch 语句?

下面通过几个实际编程场景的例子来演示 switch 语句的用法。

示例一:简易菜单选择器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <stdio.h>

int main() {
int choice;
printf("请选择一个操作:\n");
printf("1. 加法\n");
printf("2. 减法\n");
printf("3. 乘法\n");
printf("4. 除法\n");
printf("请输入您的选择 (1-4): ");
scanf("%d", &choice);

switch (choice) {
case 1:
printf("您选择了加法操作。\n");
// 在这里添加加法逻辑
break;
case 2:
printf("您选择了减法操作。\n");
// 在这里添加减法逻辑
break;
case 3:
printf("您选择了乘法操作。\n");
// 在这里添加乘法逻辑
break;
case 4:
printf("您选择了除法操作。\n");
// 在这里添加除法逻辑
break;
default:
printf("无效的选择,请输入1到4之间的数字。\n");
break;
}

return 0;
}

解释: 这个例子根据用户输入的整数 choice 来执行不同的操作。如果输入1,执行加法;输入2,执行减法,以此类推。如果输入1-4之外的数字,default 分支会处理无效输入。每个 case 后面的 break 确保了在执行完当前分支后,程序会跳出 switch 语句。

示例二:字符判断

switch 语句也可以用于字符类型,因为字符在C语言中本质上也是整型(ASCII码)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>

int main() {
char grade;
printf("请输入您的成绩等级 (A, B, C, D, F): ");
scanf(" %c", &grade); // 注意 %c 前面的空格,用于吸收前一个输入留下的换行符

switch (grade) {
case 'A':
printf("优秀!\n");
break;
case 'B':
printf("良好!\n");
break;
case 'C':
printf("中等!\n");
break;
case 'D':
printf("及格!\n");
break;
case 'F':
printf("不及格!\n");
break;
default:
printf("无效的成绩等级。\n");
break;
}

return 0;
}

解释: 这里根据输入的字符 grade 来判断成绩等级。case 'A': 等价于 case 65:(因为字符 ‘A’ 的ASCII码是65)。

示例三:“穿透”(Fall-through)的利用

虽然通常我们使用 break 来防止穿透,但有时穿透是故意的,可以用来执行多个 case 共享的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>

int main() {
int month;
printf("请输入月份数字 (1-12): ");
scanf("%d", &month);

printf("这个月有 ");
switch (month) {
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
printf("31");
break;
case 4: case 6: case 9: case 11:
printf("30");
break;
case 2:
printf("28或29"); // 简化处理,不考虑闰年
break;
default:
printf("无效的月份");
break;
}
printf(" 天。\n");

return 0;
}

解释: 在这个例子中,多个 case (如 case 1: case 3: ...)后面没有 break,这使得它们会“穿透”到下一个有 break 的 case 或者 default。这样,对于所有有31天的月份,它们都共享同一行 printf("31"); 代码,避免了代码重复。

💻 配套习题

第一题 (选择题)

以下关于C语言 switch 语句的描述,哪一项是不正确的?

A. switch 语句中的 expression 可以是 int 或 char 类型。

B. case 后面的 constant_expression 必须是常量。

C. 如果 switch 语句中没有 break 语句,程序会继续执行下一个 case 的代码。

D. switch 语句能够直接判断浮点数(如 double 类型)的大小范围。

第二题 (填空题)

在C语言的 switch 语句中,如果某个 case 分支的代码执行完毕后,没有遇到 break 语句,程序会继续执行下一个 case 分支的代码,这种现象被称为 ______。

第三题 (代码输出题)

阅读下面的C代码,并写出其输出结果:

#include <stdio.h>
int main() {
int x = 2;
switch (x) {
case 1:
printf("One\n");
case 2:
printf("Two\n");
case 3:
printf("Three\n");
default:
printf("Other\n");
}
return 0;
}

第四题 (概念辨析题)

判断题: default 关键字在 switch 语句中是必须的,否则程序会报错。

A. 正确

B. 错误

第五题 (编程题)

编写一个C程序,模拟一个简单的交通灯系统。程序接收一个字符输入,代表交通灯的颜色(’R’ 代表红灯,’Y’ 代表黄灯,’G’ 代表绿灯)。使用 switch 语句根据输入的颜色输出对应的提示信息:

‘R’:输出 “Stop! Red light.”

‘Y’:输出 “Caution! Yellow light.”

‘G’:输出 “Go! Green light.”

其他输入:输出 “Invalid light color.”

💡 习题讲解

第一题解析

答案:D

A. switch 语句中的 expression 可以是 int 或 char 类型。

正确。 switch 语句的表达式必须是整型,int 和 char 都属于整型家族(char 实际上存储的是字符的ASCII码,是整数)。

B. case 后面的 constant_expression 必须是常量。

正确。 case 标签后面只能跟常量值(字面量或用 const 定义的常量),不能是变量。

C. 如果 switch 语句中没有 break 语句,程序会继续执行下一个 case 的代码。

正确。这就是 switch 的“穿透”特性。当一个 case 匹配成功后,如果没有 break,程序会继续执行其后的所有 case(包括 default)的代码,直到遇到 break 或 switch 语句结束。

D. switch 语句能够直接判断浮点数(如 double 类型)的大小范围。

不正确。 switch 语句的 expression 必须是整型表达式,不能是 float 或 double 类型。它也无法直接判断大小范围(如 > 10 或 < 5),只能进行精确的等值匹配。判断浮点数范围或不等式通常需要使用 if-else if-else 结构。

第二题解析

答案: 穿透 (或 fall-through)

讲解: 这是一个关键概念。switch 语句的执行机制是,一旦找到匹配的 case ,它会从该 case 开始执行,直到遇到 break 语句或 switch 语句的末尾。如果没有 break,控制流会“穿透”到下一个 case,执行其代码,以此类推。理解这一点对于避免逻辑错误和有时故意利用这一特性(如多个 case 共享代码)非常重要。

第三题解析

答案:

Two
Three
Other

讲解:

程序开始, int x = 2; 。

switch (x) : x 的值为 2 。

程序查找匹配的 case 。case 1: 不匹配。

case 2: 匹配成功。程序开始执行 printf("Two\n");,输出 “Two”。

case 2: 后面 没有 break 语句。因此,程序会继续“穿透”到 case 3:。

执行 printf("Three\n");,输出 “Three”。

case 3: 后面 没有 break 语句。程序会继续“穿透”到 default:。

执行 printf("Other\n");,输出 “Other”。

default: 后面虽然也没有 break,但它是 switch 的最后一个分支,所以 switch 语句在此结束。

程序返回 0,结束。 这个题目很好地考察了对 switch 语句中 break 作用的理解。

第四题解析

答案: B (错误)

讲解: default 关键字是可选的。它的作用是当 switch 表达式的值与所有 case 标签的值都不匹配时,提供一个备选的执行路径。如果 default 不存在,并且没有 case 匹配成功,那么 switch 语句将不执行任何代码,直接跳过。程序不会因此报错。

第五题解析

答案: 见下方代码及讲解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>

int main() {
char light_color;
printf("请输入交通灯颜色 (R/Y/G): ");
scanf(" %c", &light_color);

switch (light_color) {
case 'R':
printf("Stop! Red light.\n");
break;
case 'Y':
printf("Caution! Yellow light.\n");
break;
case 'G':
printf("Go! Green light.\n");
break;
default:
printf("Invalid light color.\n");
break;
}

return 0;
}

讲解:

包含头文件:#include <stdio.h> 是必需的,因为它包含了 printf 和 scanf 函数的声明。

声明变量:char light_color; 声明一个字符变量来存储用户输入的颜色。

获取用户输入:

printf("请输入交通灯颜色 (R/Y/G): "); 提示用户输入。

scanf(" %c", &light_color); 读取用户输入的字符。注意 %c 前面的空格,这是一个小技巧,用于吸收之前输入操作可能留下的换行符,防止它被 scanf 误读为当前的字符输入。

使用 switch 语句 :

switch (light_color):根据 light_color 的值进行判断。

case 'R': :当 light_color 是字符 ‘R’ 时,执行此分支。printf("Stop! Red light.\n"); 输出对应的提示。

break; :非常重要,确保在执行完当前 case 后跳出 switch 语句,避免“穿透”到其他 case。

case 'Y': 和 case 'G': 类似处理。

default: :如果 light_color 不匹配 ‘R’, ‘Y’, ‘G’ 中的任何一个,则执行 default 分支,输出 “Invalid light color.”。 这个编程题考察了 switch 语句的基本结构、字符类型的使用以及 break 语句的正确应用。