第 10 章 选项太多怎么办——switch 与三目
🏗️ 前情回顾:上章你问了「两个岔路口够用——但如果选项有七八个呢?」这一章就是答案。switch-case 处理「多选一」干净利落,三目运算符
? :让你一句话搞定简单的二选一。
🎯 本章目标
学完这一章,你能:
- 用
switch-case写出清晰的多分支代码 - 理解
break的作用——阻止"穿透" - 知道什么时候该用
default兜底 - 用三目运算符
? :简洁地表达"二选一" - 判断什么时候用
switch-case、什么时候用if-else
📖 故事引入
放学后你走到自动售货机前,想买瓶饮料。
机器屏幕上显示菜单:1-可乐、2-雪碧、3-芬达、4-矿泉水、5-果汁……
你按了"3",机器"咕咚"一声掉出一瓶芬达。
这个过程的代码逻辑大概是:
如果 选了 1 → 出可乐
如果 选了 2 → 出雪碧
如果 选了 3 → 出芬达
...用 else if 写也能搞定,但你要是看代码——密密麻麻一排 else if,像一堵墙。而且每次判断都要把"选了哪个数字"重新算一遍,不够利索。
有没有一种写法,直接告诉程序:"看这个数字是多少,跳到对应入口"?
有,这就是 switch-case。
🧱 知识讲解
10.1 switch-case 基本语法
switch-case 就像一个"跳转表"——你给一个整数(或字符),程序直接跳到对应的 case 标签开始执行:
switch (表达式) {
case 值1:
// 表达式 == 值1 时执行这里
break;
case 值2:
// 表达式 == 值2 时执行这里
break;
default:
// 所有 case 都不匹配时执行这里
}自动售货机的例子:
int choice;
cin >> choice;
switch (choice) {
case 1:
cout << "你选了:可乐" << endl;
break;
case 2:
cout << "你选了:雪碧" << endl;
break;
case 3:
cout << "你选了:芬达" << endl;
break;
case 4:
cout << "你选了:矿泉水" << endl;
break;
case 5:
cout << "你选了:果汁" << endl;
break;
default:
cout << "没有这个编号,请重新选择" << endl;
}对比 else if 版本,switch-case 的好处一目了然:结构清晰,一眼就能看出有多少个选项,每个选项做什么。
10.2 break 的作用:制止"穿透"
❌ 先看看这段代码——有什么问题?
int n = 2;
switch (n) {
case 1: cout << "A";
case 2: cout << "B";
case 3: cout << "C";
}
// 输出:BC ← 嗯?怎么 B 和 C 都出来了?输入 2,期望只输出 "B",结果 "BC" 都出来了!这是因为 switch-case 有个特别的设计——case 标签只是"入口",不是"出口"。程序从匹配的 case 冲进去,然后就一路向下狂奔,把后面的 case 全执行一遍,直到遇到 break 或 switch 结束。
这叫做穿透——不加 break,程序就像瀑布一样从当前 case 一路流到底。
✅ 正确版本:每个 case 末尾加 break
int n = 2;
switch (n) {
case 1:
cout << "A" << endl;
break;
case 2:
cout << "B" << endl; // 输出 B
break; // 然后跳出,不往下掉
case 3:
cout << "C" << endl;
break;
}
// 输出:B ← 这才是我们要的💡 穿透是 bug 的温床。除非你刻意利用穿透(下一节会讲),否则每个 case 末尾都加
break。
10.3 巧用穿透:合并相同处理
有时候多个 case 做同样的事,利用穿透可以写得非常漂亮:
int month;
cin >> month;
switch (month) {
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
cout << "31天" << endl;
break;
case 4: case 6: case 9: case 11:
cout << "30天" << endl;
break;
case 2:
cout << "28天或29天" << endl;
break;
default:
cout << "无效月份" << endl;
}看!1、3、5、7、8、10、12 月都是 31 天,写在一排 case 标签里,共享同一段代码。这比 if (month==1 || month==3 || ...) 清爽多了。
另一个常用场景——成绩等级简化版:
int score;
cin >> score;
switch (score / 10) { // 除以 10 取整:95→9,82→8,67→6
case 10: // 100 分
case 9:
cout << "A" << endl;
break;
case 8:
cout << "B" << endl;
break;
case 7:
cout << "C" << endl;
break;
case 6:
cout << "D" << endl;
break;
default:
cout << "E" << endl;
}💡 这里
score / 10是整数除法,能把分数映射到 0–10 的区间,再用 switch 一锤定音。这是 switch 的经典用法。
10.4 switch-case 的限制
switch 不是万能的,它有明确的限制:
switch 后面的表达式必须是整型或字符型(
int、long long、char,以及后面会学的枚举)。不能是double、不能是string。case 后面必须是常量——不能是变量,不能是范围(你不能写
case 60..100:)。各 case 的值不能重复——编译器直接报错。
这些限制意味着:switch-case 适合"精确匹配某个值"的场景。如果你需要判断"分数 > 90",那还是用 if-else。
10.5 三目运算符 ? ::最简单的二选一
有时候你要做的判断非常简单——就一行赋值:
// if-else 写法
int result;
if (a > b) {
result = a;
} else {
result = b;
}天哪,写了 5 行就为了取个最大值。C++ 有个更简洁的写法——三目运算符 ? ::
int result = (a > b) ? a : b; // 一行搞定!格式:
条件 ? 成立时的值 : 不成立时的值翻译成人话:"条件成立吗?成立就选冒号前面的,不成立就选冒号后面的。"
更多例子:
int absValue = (x >= 0) ? x : -x; // 求绝对值
string status = (score >= 60) ? "及格" : "不及格"; // 输出文字
cout << ((n % 2 == 0) ? "偶数" : "奇数") << endl; // 直接输出⚠️ 三目运算符不要嵌套!
a ? b : c ? d : e这种写法只有写的人自己能看懂(过三天自己也不一定看得懂)。简单二选一用它,复杂的请老老实实写if-else。
10.6 switch-case vs if-else:怎么选
| 场景 | 推荐 | 原因 |
|---|---|---|
| 判断范围(> <) | if-else | switch 不支持范围 |
| 精确匹配几个值 | switch-case | 结构更清晰 |
| 条件涉及逻辑运算 | if-else | switch 里不能写 && |
| 选项很多(5+) | switch-case | 代码更整洁 |
| 简单二选一赋值 | 三目 ? : | 一行搞定 |
没有绝对的优劣,选让代码更清晰好读的那个。
✋ 动手试试
试试 1:写一个程序,输入 1–7 的数字,输出对应的星期几(1→星期一,2→星期二……)。用 switch-case。
试试 2:把第 9 章的成绩评级程序(A/B/C/D/E)用 switch-case 改写一遍。对比两种写法,你更喜欢哪个?
试试 3:用三目运算符写一个"判断奇偶"的程序——输入一个整数,输出"奇数"或"偶数"。只用一行 cout。
试试 4:故意不给每个 case 写 break,观察"穿透"现象。比如输入 2,看看哪些 case 被执行了。
⚠️ 你踩过这些坑吗
- [ ] 坑 1:忘了写 break——程序从匹配的 case 一路执行到底,把后面的 case 代码也跑了。每个 case 末尾加
break,除非你故意的。 - [ ] 坑 2:用 switch 判断范围——
case 60..100:不合法,范围判断用if-else。 - [ ] 坑 3:switch 里用 string——
switch (name) { case "小明": ... }C++ 不支持,字符串比较用if-else。 - [ ] 坑 4:三目运算符写得太复杂——
int r = a > b ? (c > d ? e : f) : (g > h ? i : j);谁能看懂?三目只做简单二选一,复杂的回到if-else。
📝 练习
基础题
1. 选择题
(1)以下 switch 语句中,n = 2 时输出什么?
switch (n) {
case 1: cout << "A"; break;
case 2: cout << "B";
case 3: cout << "C"; break;
default: cout << "D";
}A. B B. BC C. C D. BCD
(2)int m = (x > y) ? x : y; 这行代码的作用是:
A. 判断 x 是否大于 y B. 把较大的值赋给 m C. 交换 x 和 y D. 比较 x 和 y 是否相等
(3)以下哪个不能放在 switch 后面的括号里?
A. int 变量 B. char 变量 C. string 变量 D. 算术表达式
2. 填空题
(1)switch 语句中,_________ 关键字用于阻止穿透。
(2)_________ 关键字用于处理所有 case 都不匹配的情况。
(3)x > 0 ? 1 : -1 的结果:当 x = 5 时是 ___,当 x = -3 时是 ___。
3. 代码找错
以下代码有什么问题?修改成正确的版本:
int day;
cin >> day;
switch (day) {
case 1: cout << "星期一";
case 2: cout << "星期二";
case 3: cout << "星期三";
}4. 读代码写输出
int n = 8;
cout << (n % 2 == 0 ? "YES" : "NO") << endl;写出上面代码的输出结果:_________
提高题
5. 编程题 — 简易计算器(switch 版)
用 switch-case 改写第 9 章的计算器程序。输入两个整数和一个运算符(+ - * /),用 switch 判断运算符,输出结果。除数为 0 时提示错误。
6. 编程题 — 季节判断
输入月份(1–12),输出对应的季节:
- 3–5 月:春天
- 6–8 月:夏天
- 9–11 月:秋天
- 12、1、2 月:冬天
用 switch-case 的穿透特性,尽量用最少的代码。
7. 编程题 — 成绩评级(完整版)
输入一个 0–100 的分数:
- 如果是有效的分数(0~100),用 switch 输出等级 A/B/C/D/E
- 如果无效,输出"分数不合法"
- 额外:如果分数是 100 分,输出"满分!太厉害了!"
挑战题
8. 编程题 — 日期合法性
输入年、月、日,判断这个日期是否合法(例如 2024-2-30 不合法)。需要考虑:
- 大月(31 天):1、3、5、7、8、10、12
- 小月(30 天):4、6、9、11
- 2 月:闰年 29 天,平年 28 天
用 switch-case 处理月份,结合第 9 章的闰年判断。
9. 编程题 — 星座查询
输入月份和日期,输出对应的星座。例如:3月21日~4月19日是白羊座。用 switch-case 嵌套 if 实现。(提示:先用 switch 分月,再在每个月里用 if 判断日期范围。)
🧠 本章小结
┌─────────────────────────────────────────────────────────┐
│ │
│ switch-case:给一个值,跳到对应入口 │
│ │
│ break = 出口(不加就穿透) │
│ default = 兜底(所有 case 都不匹配时走这里) │
│ │
│ switch 限制:只能整型/字符型,case 必须是常量 │
│ │
│ 三目运算符:条件 ? 成立值 : 不成立值 │
│ → 简单二选一的神器,别嵌套! │
│ │
│ 选择指南: │
│ 范围判断 → if-else │
│ 精确匹配多值 → switch-case │
│ 简单二选一 → 三目 ? : │
│ │
└─────────────────────────────────────────────────────────┘📝 配套练习
共8题。switch语法简单——重点是"什么时候用switch vs if"。J0036(买铅笔)和J0039(电费)教分段决策的应用价值。。★核心(课堂必做) ◆拓展(课后练习)
| 级别 | 题号 | 链接 | 覆盖知识点 |
|---|---|---|---|
| ★ 核心 | J0034 | https://hydro.ac/d/srqc/p/J0034 | switch-case、break、default |
| ◆ 拓展 | J0042 | https://hydro.ac/d/srqc/p/J0042 | if-else、计数、? : 三目 |
| ◆ 拓展 | J0043 | https://hydro.ac/d/srqc/p/J0043 | 排序、条件判断、三输出 |
| ◆ 拓展 | luogu-B2048 | https://hydro.ac/p/luogu-B2048 | switch、分段计费 |
| ◆ 拓展 | J0032 | https://hydro.ac/d/srqc/p/J0032 | if-else链、BMI分段 |
| ◆ 拓展 | J0036 | https://hydro.ac/d/srqc/p/J0036 | if-else、最小值、三选一 |
| ◆ 拓展 | J0039 | https://hydro.ac/d/srqc/p/J0039 | 分段计费、else-if链、边界 |
| ◆ 拓展 | luogu-B2050 | https://hydro.ac/p/luogu-B2050 | if-else、三角形条件、逻辑&& |
💡 练习建议:先完成 1 道★核心题,确保掌握本章基本方法;再完成 7 道◆拓展题,覆盖不同变式和细节。
配套练习
共8题。switch语法简单——重点是"什么时候用switch vs if"。J0036(买铅笔)和J0039(电费)教分段决策的应用价值。★核心(课堂必做) · ◆拓展(课后练习)
| 级别 | 题号 | 链接 | 覆盖知识点 |
|---|---|---|---|
| ★ 核心 | J0034 | https://hydro.ac/d/srqc/p/J0034 | switch-case、break、default |
| ◆ 拓展 | J0042 | https://hydro.ac/d/srqc/p/J0042 | if-else、计数、? : 三目 |
| ◆ 拓展 | J0043 | https://hydro.ac/d/srqc/p/J0043 | 排序、条件判断、三输出 |
| ◆ 拓展 | luogu-B2048 | https://hydro.ac/p/luogu-B2048 | switch、分段计费 |
| ◆ 拓展 | J0032 | https://hydro.ac/d/srqc/p/J0032 | if-else链、BMI分段 |
| ◆ 拓展 | J0036 | https://hydro.ac/d/srqc/p/J0036 | if-else、最小值、三选一 |
| ◆ 拓展 | J0039 | https://hydro.ac/d/srqc/p/J0039 | 分段计费、else-if链、边界 |
| ◆ 拓展 | luogu-B2050 | https://hydro.ac/p/luogu-B2050 | if-else、三角形条件、逻辑&& |
练习建议:先在课堂完成 1 道★核心题,掌握本章基本方法;课后完成 7 道◆拓展题,覆盖不同变式和细节。
自查清单:
- [ ] 我能写出带
break和default的 switch-case 语句 - [ ] 我理解"穿透"——知道什么时候故意用它,什么时候必须加
break - [ ] 我知道 switch-case 的限制(不能是 string,不能是范围)
- [ ] 我会用三目运算符
? :做简单的二选一 - [ ] 我能根据场景选择 switch-case 还是 if-else
🚀 下章预告:判断一次就跑太浪费了——同一件事做 100 遍,才是计算机真正的强项。下章学
for循环,3 行代码干 100 行的活。