在 C++ 中,switch 语句是一种专门用来匹配多个固定值的多分支选择结构。相比 if...else 语句,当我们需要拿同一个变量去匹配几个确定的固定选项时,使用 switch 语句会让分支排列更加工整直观。
C++ switch 语法
在 C++ 中,switch 语句通过 switch、case、break 和 default 这几个关键字配合使用。
语法:
switch (判断值) {
case 取值 1:
// 语句块 1
break;
case 取值 2:
// 语句块 2
break;
default:
// 默认语句块
break;
}说明:
从英文意思来看,switch 是 “开关”,case 是 “情况”,break 是 “断开”,default 是 “默认”。小伙伴们结合英文原意来理解,就很容易记住了。
程序执行时,会先计算小括号里 “判断值” 的结果,再从上往下依次对比哪一个 case 的取值与它相等。找到匹配的分支后就会执行里面的代码,遇到 break; 便跳出整个 switch 结构。如果所有 case 都不匹配,则执行 default 后面的代码。
需要注意的是,case 和 default 后面写的是英文冒号(:),而不是英文分号(;)。
C++ switch 示例
在实际开发中,switch 语句非常常用,下面我们通过几个简单的例子来看看它是如何使用的。
示例 1:switch 语句的基本用法
#include <iostream>
int main() {
int day = 5;
switch (day) {
case 1:
std::cout << "今天是星期一\n";
break;
case 2:
std::cout << "今天是星期二\n";
break;
case 3:
std::cout << "今天是星期三\n";
break;
case 4:
std::cout << "今天是星期四\n";
break;
case 5:
std::cout << "今天是星期五\n";
break;
case 6:
std::cout << "今天是星期六\n";
break;
default:
std::cout << "今天是星期日\n";
break;
}
return 0;
}运行结果如下。
今天是星期五分析:
在这个例子中,变量 day 的值为 5。程序从第一个 case 开始往下对比,直到匹配上 case 5,输出 “今天是星期五”。紧接着遇到 break;,直接退出整个 switch 结构,后面的 case 6 和 default 都不会再执行了。
除了匹配整数之外,switch 也经常用来匹配 char 字符类型,因为字符在底层同样是按整数(ASCII 码)存储的。
示例 2:使用 switch 匹配字符
#include <iostream>
int main() {
char grade = 'B';
switch (grade) {
case 'A':
std::cout << "优秀\n";
break;
case 'B':
std::cout << "良好\n";
break;
case 'C':
std::cout << "及格\n";
break;
default:
std::cout << "需要继续努力\n";
break;
}
return 0;
}运行结果如下。
良好分析:
grade 是 char 类型的变量,值为 'B',因此匹配到 case 'B' 分支,输出 “良好”。如果把 grade 的值改为 'D',由于前面的 case 都无法匹配,程序就会进入 default 分支,输出 “需要继续努力”。
这里还要留意,每个 case 后面的取值都必须是整数、字符或 const 常量等固定值。如果像下面这样把普通变量 target 写在 case 后面,编译时就会直接报错:
int target = 2;
switch (day) {
case target:
std::cout << "今天是星期二\n";
break;
}注意
判断值只能是整型或枚举:switch 小括号里的判断值必须是 int、char、short、long 等整型,或者是后面会学习的枚举类型,不能使用 double 浮点数或字符串。
case 的取值不能重复:在同一个 switch 语句中,各个 case 后面的取值必须互不相同,否则编译时会直接报错。
对于 switch 和 case 的匹配过程,大家都很容易理解。但不少初学的小伙伴会感到好奇:“为什么每个 case 分支最后都要写一句 break; 呢?如果不写会发生什么?” 下面我们来看一个例子。
示例 3:漏写 break 导致的穿透
#include <iostream>
int main() {
int day = 5;
switch (day) {
case 1:
std::cout << "今天是星期一\n";
case 2:
std::cout << "今天是星期二\n";
case 3:
std::cout << "今天是星期三\n";
case 4:
std::cout << "今天是星期四\n";
case 5:
std::cout << "今天是星期五\n";
case 6:
std::cout << "今天是星期六\n";
default:
std::cout << "今天是星期日\n";
}
return 0;
}运行结果如下。
今天是星期五
今天是星期六
今天是星期日分析:
day 的值明明是 5,为什么除了输出 “今天是星期五” 之外,还把后面的星期六和星期日也一并打印出来了呢?其实,这就是缺少 break 语句的结果。
在 switch 语句中,case 只相当于进入分支的一个 “入口标签”,并不会自动把各个分支隔开。程序从 case 5 进入后,因为末尾没有遇到 break; 跳出,就会顺着往下把 case 6 和 default 里的代码也全部执行一遍,直到整个 switch 结束。
这种现象称为 “case 穿透”。因此,当各个分支彼此独立时,小伙伴们一定要记得在每个 case 分支末尾加上 break;。至于放在最末尾的 default 分支,后面已经没有其他分支了,break; 可加可不加,平时统一加上会更稳妥。
深入了解 C++ switch 语句
掌握基本用法后,我们再来看看 switch 语句的常见合并写法,以及它与 if...else 的选型原则。
1. 多个 case 共用一组语句
当多个不同的取值需要执行同一段逻辑时,我们可以反过来利用穿透特性,把多个 case 连在一起写。
示例 4:多个 case 共用一组语句
#include <iostream>
int main() {
int day = 3;
switch (day) {
case 1:
case 2:
case 3:
case 4:
case 5:
std::cout << "工作日\n";
break;
case 6:
case 7:
std::cout << "周末\n";
break;
default:
std::cout << "输入的星期数不正确\n";
break;
}
return 0;
}运行结果如下。
工作日分析:
在这个例子中,当 day 为 1 到 5 中的任意一个整数时,都会顺着执行 case 5 后面的代码,输出 “工作日” 并遇到 break; 跳出。当 day 为 6 或 7 时,则会输出 “周末”。
此外,switch 语句中的 default 分支并不是必须写的。当没有任何 case 匹配成功且省略了 default 分支时,整个 switch 语句会直接结束,不会做任何处理。
2. switch 与 if...else 如何选择?
在实际开发中,switch 和 if...else 语句都能实现多分支判断,我们可以按照以下 2 条标准来选择:
- 优先使用 switch 语句:拿同一个整型或字符变量去匹配几个确定的固定值时,分支排列更加工整清晰。
- 使用 if...else 语句:需要判断数值区间,比如判断分数是否在 60 到 80 之间,或者需要判断浮点数、字符串等类型时,只能使用
if...else语句。
常见问题
1. 为什么在 case 分支里直接定义新变量会报错?
不少小伙伴在某个 case 分支里直接写下 int bonus = 100; 时,会发现编译器报错。这是因为整个 switch 的花括号 {} 内部属于同一个作用域,单个 case 只是一个跳转标签,并不会单独隔出一块封闭的区域。
如果在 case 1 里直接定义并初始化变量 bonus,一旦程序跳过 case 1 直接进入后面的 case 2,这行初始化代码就被跳过了,但变量名在后面依然可见。C++ 为了防止访问未初始化的变量,会直接禁止这种写法。
解决办法非常简单:只要需要在某个 case 分支内部定义新变量,用一对花括号 {} 把该分支括起来即可,比如写成 case 1: { int bonus = 100; break; }。这样新变量就只在这对花括号内部有效,编译就能顺利通过了。
