switch-case 语句
需要预先学习:
1. switch-case 语句
switch-case 语句是一种多分支选择结构,它根据一个整型表达式的值跳转到匹配的 case 标签处执行。基本语法如下:
switch (表达式)
{
case 常量1:
// 匹配常量1时执行的代码
break;
case 常量2:
// 匹配常量2时执行的代码
break;
default:
// 没有任何 case 匹配时执行的代码
break;
}
switch 后面括号中的表达式必须是整型(int、char、enum 等),case 后面必须是常量表达式。程序会拿表达式的值依次与每个 case 的值比较,找到匹配的就跳过去执行;如果没有任何匹配,就执行 default(如果有的话)。
1.1 break 的用法
break 语句用于跳出 switch 结构。如果没有 break,程序会继续执行下一个 case 中的代码——这个特性被称为"穿透"(fall-through)。
有 break 的情况(正常行为):
int day = 3;
switch (day)
{
case 1:
std::cout << "星期一";
break; // 跳出 switch
case 2:
std::cout << "星期二";
break;
case 3:
std::cout << "星期三";
break;
default:
std::cout << "未知";
break;
}
// 输出:星期三
没有 break 的情况(穿透):
int day = 3;
switch (day)
{
case 1:
std::cout << "星期一";
case 2:
std::cout << "星期二";
case 3:
std::cout << "星期三"; // 从这里开始匹配
default:
std::cout << "未知";
}
// 输出:星期三未知
// 匹配 case 3 后没有 break,继续执行 default
穿透并非总是坏事。有时候你有意希望多个 case 共享同一段代码:
switch (day)
{
case 1:
case 2:
case 3:
case 4:
case 5:
std::cout << "工作日";
break;
case 6:
case 7:
std::cout << "周末";
break;
}
理解要点:
case只是一个"入口标签",不是"独立区块"。进入后如果没有break拦住,就会一路往下。
1.2 在 case 中定义变量
如果在你的代码逻辑中,不同 case 需要定义同名的变量,你需要分别用花括号 {} 把它们包起来,形成独立的作用域:
switch(x)
{
case 1:
{
int a = 10; // case 1 中定义的变量
std::cout << a;
break;
}
case 2:
{
int a = 20; // case 2 中定义的变量
std::cout << a;
break;
}
default:
std::cout << "其他情况";
break;
}
注意:原因是
case标签之后的所有代码都在同一个作用域中,所以如果不加花括号,case 1和case 2中的int a就会冲突。
2. switch-case 与 if-else 的比较
switch-case 和 if-else if-else 都能实现多分支选择,但它们的适用场景和底层行为不同。
2.1 条件限制
switch-case 最关键的限制是:case 标签必须是常量表达式,不能是变量。
int x = 10;
switch (x)
{
case 1: // 常量
break;
case 2 + 3: // 常量表达式,编译期可计算
break;
case y: // 错误!y 是变量,不是常量
break;
}
if-else if-else 没有这个限制,每个条件可以是任意表达式:
int a = 10;
int b = 20;
if (a > b) // 变量参与的关系表达式
{
// ...
}
else if (a + b > 50) // 任意表达式都可以
{
// ...
}
另外,switch 的表达式必须是整型,不能是 float、double 或 std::string。
2.2 效率层面
在某些情况下,switch-case 比一长串 if-else if-else 效率更高。
if-else if-else 是逐个检查的——条件越多,越到后面的分支等待时间越长(O(n))。
而编译器可以为 switch-case 生成跳转表——当 case 的值比较密集时,编译器会生成一张表,直接算出目标地址一步跳过去(接近 O(1)):
跳转表示意(编译器生成):
case 值 跳转地址
-------- ---------
1 → 0x1000
2 → 0x1008
3 → 0x1010
4 → 0x1018
注:在现代编译器和硬件上,除非分支特别多,二者效率差异通常微乎其微——可读性优先。


