5.“多重选择”:switch-case 语句
“多重选择”:switch-case 语句
本章导读 (The Hook)
在上一章,我们学会了用 if-else if-else 来处理多重选择,就像在十字路口根据不同的情况选择不同的道路。这非常强大,但当选项变得非常多的时候,代码就会显得有些冗长和笨拙。
想象一下,你正在为一部电梯编写程序。电梯里有 20 个楼层按钮。如果用 if-else if 来写,代码可能会是这样:if (按钮 == 1) { 去 1 楼 } else if (按钮 == 2) { 去 2 楼 } else if (按钮 == 3) { 去 3 楼 } ...
一直写到 20 楼!这太繁琐了。
C++ 为我们提供了另一种更优雅、更清晰的工具来处理这种情况,它就是 switch-case 语句。你可以把它想象成电梯的控制面板:你按下一个特定的按钮(一个确定的值),程序就直接跳转到对应的楼层(执行对应的代码),而不需要挨个去问“是不是这个?是不是那个?”。
当你的判断条件是“检查某一个变量是否等于某个具体的值”时,switch-case 就是你的最佳选择。
专业术语速查表 (Glossary)
点击展开/折叠本章术语表
switch- 通俗比喻:电梯的“控制面板”。你在括号
()里放入你想要检查的那个“按钮编号”(变量)。 - 解释:C++ 的关键字,用于开始一个多路分支选择结构。它会计算括号内表达式的值。
- 通俗比喻:电梯的“控制面板”。你在括号
case- 通俗比喻:面板上的一个具体的“楼层按钮”。后面跟着一个常量值(比如
1,'A')和一个冒号:。 - 解释:C++ 的关键字,用于定义一个分支的入口。当
switch表达式的值与case后的常量值相等时,程序将从此case开始执行。
- 通俗比喻:面板上的一个具体的“楼层按钮”。后面跟着一个常量值(比如
break- 通俗比喻:到达指定楼层后,按下“开门并停止”的按钮。它告诉电梯:“任务完成,停在这里,不要再往下走了!”
- 解释:C++ 的关键字,用于立即跳出当前的
switch-case结构。这是switch语句中至关重要且最容易被遗忘的部分。
default- 通俗比喻:电梯面板上的“紧急呼叫”或“无效按钮”提示。当按下的按钮(变量的值)在所有
case中都找不到时,程序就会执行default里的指令。 - 解释:C++ 的关键字,定义了当没有任何
case匹配时要执行的默认代码块。它类似于if-else if-else链条中最后的那个else。
- 通俗比喻:电梯面板上的“紧急呼叫”或“无效按钮”提示。当按下的按钮(变量的值)在所有
贯穿 (Fall-through)
- 通俗比喻:电梯到达 3 楼后,门没开,反而径直掉到了 2 楼、1 楼... 这种危险行为,就是因为你忘记在 3 楼按下
break按钮! - 解释:在
switch-case中,如果一个case块的末尾没有break语句,程序会继续执行下一个case块中的代码,而不会进行条件判断。
- 通俗比喻:电梯到达 3 楼后,门没开,反而径直掉到了 2 楼、1 楼... 这种危险行为,就是因为你忘记在 3 楼按下
核心概念讲解 (The Core Concept)
1. switch-case 的基本结构
我们直接来看一个经典的“星期几”例子。
语法:
switch (要检查的变量) { case 值1: // 如果变量等于值1,执行这里的代码 break; // 然后跳出 switch case 值2: // 如果变量等于值2,执行这里的代码 break; // 然后跳出 switch // ...可以有更多的 case default: // 如果变量不等于上面任何一个值,执行这里的代码 break; // default 里的 break 在逻辑上不是必须的,但写上是好习惯 }代码示例:今天星期几?
#include <iostream> int main() { int day = 0; // 提示用户输入数字 std::cout << "请输入一个数字 (1-7) 来代表星期几: "; std::cin >> day; switch (day) { case 1: std::cout << "今天是星期一。" << std::endl; break; case 2: std::cout << "今天是星期二。" << std::endl; break; case 3: std::cout << "今天是星期三。" << std::endl; break; case 4: std::cout << "今天是星期四。" << std::endl; break; case 5: std::cout << "今天是星期五。" << std::endl; break; case 6: std::cout << "今天是星期六。" << std::endl; break; case 7: std::cout << "今天是星期日。" << std::endl; break; default: std::cout << "错误:请输入 1 到 7 之间的数字。" << std::endl; break; } return 0; }这段代码比用七个
if-else if要清晰得多。程序会直接根据day的值,跳转到匹配的case执行。
2. break 的重要性:致命的“贯穿”现象
如果我们故意去掉几个 break,会发生什么?
// 危险示范:忘记写 break
switch (day) {
case 6:
std::cout << "今天是星期六。" << std::endl;
// 没有 break!
case 7:
std::cout << "今天是星期日。" << std::endl;
break;
default:
std::cout << "今天是工作日。" << std::endl;
break;
}- 如果用户输入
6,程序会跳转到case 6:,打印 "今天是星期六。"。但由于没有break,它不会停下,而是会直接贯穿到下一个case,继续执行case 7:的代码,打印 "今天是星期日。"! - 这就是“贯穿 (Fall-through)”,通常是我们不希望看到的 Bug。
敲黑板!
每个 case 块的结尾,几乎总是应该有一个 break;! 除非你是故意要利用“贯穿”特性(这在某些高级技巧中会用到,但新手阶段请一律加上 break)。
动手试试 (Try It Yourself!)
简易自动售货机
- 编写一个程序,模拟一个只卖三种饮料的售货机。
- 提示用户输入一个编号(1 代表可乐,2 代表雪碧,3 代表矿泉水)。
- 使用
switch-case结构,根据用户的输入打印出对应的饮料名称。 - 如果用户输入了其他编号,使用
default来提示“商品不存在”。
月份与季节 (利用贯穿特性)
- 编写一个程序,让用户输入月份(1-12)。
- 使用
switch-case来判断这个月份属于哪个季节(简单起见,我们规定 3-5 月为春季,6-8 月为夏季,9-11 月为秋季,12, 1, 2 月为冬季)。 - 提示:你可以巧妙地利用“贯穿”特性来合并多个
case。例如:
case 3: case 4: case 5: std::cout << "这是春季。" << std::endl; break; // ... 其他季节
“防坑”指南与常见错误 (The Pitfalls)
天坑一:忘记 break
这值得我们第三次强调!忘记 break 是 switch 语句中最常见的错误,它不会导致编译失败,但会造成严重的逻辑错误。请养成写完一个 case 的逻辑后,立刻补上 break 的习惯。
限制一:switch 只能用于整数类型
switch 的括号里只能放整数类型的变量或表达式,包括 int, char, long, short, enum 等。
- 你不能 对
double或float这样的浮点数使用switch。 - 你也不能 对
string这样的字符串类型使用switch。
在这些情况下,你必须回头使用 if-else if-else。
限制二:case 后面必须是常量
case 标签后面的值必须是一个在编译时就能确定的常量或字面量。
// 正确的
case 10: ...
case 'A': ...
// 错误的
int myVar = 10;
case myVar: ... // 错误!不能使用变量
// 错误的
case score > 90: ... // 错误!不能使用表达式或范围判断switch 的本质是“跳转表”,它需要提前知道所有可能的跳转目标。而变量的值和表达式的结果在运行时才能确定,所以无法作为 case 标签。
本章小结 (The Summary)
我们又学会了一种强大的控制流工具,让我们的代码在面对多重选择时更加优雅。
switch-case是if-else if-else在特定场景下的一个更佳替代品。- 它适用于对单个整数类型变量进行等值判断的场景。
- 其核心结构由
switch,case,break,default组成。 break的作用是跳出switch结构,千万不能忘记,否则会产生“贯穿”效应。default用于处理所有case都不匹配的情况。switch有其局限性:不能用于浮点数和字符串,也不能进行范围判断。
我们现在已经完全掌握了如何让程序“做选择”。但现实世界中,很多任务是需要重复执行的。比如,游戏需要不断地刷新屏幕,网站需要不断地处理新的用户请求。如何让程序自动地重复执行某段代码呢?下一章,我们将开启一个全新的篇章——“自动重复”:for 循环。
