信奥崔老师:switch 语句

192 阅读5分钟

2.2 switch 语句

图片

1. 概念介绍

switch 语句是一种特殊的多路分支结构,它将一个变量或表达式的值与一系列 case 标签进行比较。如果匹配成功,则执行该 case 标签下的代码。它通常用于替代一长串检查同一变量是否等于多个离散值的 if-else if 语句。

2. 算法步骤

  1. 评估表达式:  计算 switch 后面括号里表达式的值。
  2. 匹配 case:  将该值与每个 case 标签后的常量值进行比较。
  3. 跳转执行:
    • 如果找到匹配的 case,程序跳转到该 case 标签处开始执行。
    • 如果找不到任何匹配的 case,且存在 default 标签,则程序跳转到 default 处执行。
    • 如果找不到匹配且没有 default,则 switch 语句什么也不做。
  4. 顺序执行与 break:
    • 一旦跳转到某个 case,程序会顺序执行下去,穿透到下一个 case,直到遇到 break 语句或 switch 结束。
    • break 语句会立即跳出整个 switch 结构。

3. 算法可视化SVG图示  3. 算法可视化 SVG 图示

图片

4. 核心特性

  • 整型判断: switch 的表达式必须是整数类型(intcharenum 等),不能是 floatdouble 或 string
  • 常量标签: case 后的值必须是编译时常量。
  • 穿透行为 (Fall-through):  如果 case 块末尾没有 break,执行流会继续进入下一个 case 块,这是 switch 最独特的特性,既是强大功能也是常见错误源。
  • default 子句:  可选,用于处理所有 case 都不匹配的情况。

5. C++代码基础实现

  #include <iostream>

  int main() {
      int day;
      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:
          case 7// 利用穿透特性
              std::cout << "周末" << std::endl;
              break;
          default:
              std::cout << "输入错误" << std::endl;
              break;
      }
      return 0;
  }

6. 优化策略

  • 编译器优化:  现代编译器通常会将 switch 语句优化为跳转表(Jump Table)或二分搜索,其效率通常高于等效的 if-else if 链。因此,当条件适用时,优先使用 switch 本身就是一种优化。
  • 合理安排 case:  将最常见的 case 放在前面可能(在某些编译器实现中)有微小的性能提升,但主要还是为了代码可读性。

7. 优缺点

  • 优点:
    • 当判断同一变量与多个离散常量时,结构清晰,可读性高。
    • 效率通常比 if-else if 链高。
    • "穿透"特性可以巧妙地用于处理多种情况执行相同代码的场景。
  • 缺点:
    • 限制性强,只能用于整型和常量判断,不能进行范围判断。
    • 容易忘记写 break,导致逻辑错误。
    • 每个 case 都必须是唯一的常量。

8. 应用场景

  • 菜单选择:  根据用户输入的数字或字符执行不同功能。
  • 状态机:  根据当前状态(通常用枚举或整数表示)转移到下一个状态。
  • 解析命令:  根据命令行参数或协议中的命令码执行不同操作。
  • 词法分析:  在编译器或解释器中,根据读取到的字符类型进行分类处理。

9. 扩展

  • C++17 switch with initialization:  可以在 switch 语句中声明和初始化一个变量,其作用域仅限于该 switch 块。

    switch (auto c = get_char(); c) {
        case 'a'/* ... */ break;
        case 'b'/* ... */ break;
        // c 在这里可见
    }
    // c 在这里不可见
    
  • Duff's Device:  一个利用 switch 穿透特性的著名C语言高级技巧,用于实现循环展开优化,但代码可读性极差,在现代C++中几乎用不到。

10. 课后配套练习

  1. 月份天数:  输入一个月份(1-12),输出该月份在平年有多少天(不考虑闰年)。
  2. 简单计算器:  输入两个整数和一个运算符(+-*/),输出计算结果。
  3. 成绩等级:  输入一个百分制成绩,先将其除以10取整,然后用switch判断等级(9-10为'A', 8为'B', 7为'C', 6为'D', 其他为'F')。
  4. 方向控制:  输入一个字符代表方向('W'-上, 'S'-下, 'A'-左, 'D'-右),输出对应的中文方向。
  5. 元音辅音判断:  输入一个小写字母,判断是元音字母(a, e, i, o, u)还是辅音字母。

点击查看答案

1. 月份天数

  #include <iostream>
  int main() {
      int month;
      std::cin >> month;
      switch (month) {
          case 1case 3case 5case 7case 8case 10case 12:
              std::cout << 31 << std::endl;
              break;
          case 4case 6case 9case 11:
              std::cout << 30 << std::endl;
              break;
          case 2:
              std::cout << 28 << std::endl;
              break;
          default:
              std::cout << "Invalid month" << std::endl;
              break;
      }
      return 0;
  }

2. 简单计算器

  #include <iostream>
  int main() {
      int a, b;
      char op;
      std::cin >> a >> op >> b;
      switch (op) {
          case '+':
              std::cout << a + b << std::endl;
              break;
          case '-':
              std::cout << a - b << std::endl;
              break;
          case '*':
              std::cout << a * b << std::endl;
              break;
          case '/':
              if (b != 0) {
                  std::cout << a / b << std::endl;
              } else {
                  std::cout << "Error: Division by zero" << std::endl;
              }
              break;
          default:
              std::cout << "Invalid operator" << std::endl;
              break;
      }
      return 0;
  }

3. 成绩等级

  #include <iostream>
  int main() {
      int score;
      std::cin >> score;
      switch (score / 10) {
          case 10:
          case 9:
              std::cout << 'A' << std::endl;
              break;
          case 8:
              std::cout << 'B' << std::endl;
              break;
          case 7:
              std::cout << 'C' << std::endl;
              break;
          case 6:
              std::cout << 'D' << std::endl;
              break;
          default:
              std::cout << 'F' << std::endl;
              break;
      }
      return 0;
  }

4. 方向控制

  #include <iostream>
  int main() {
      char dir;
      std::cin >> dir;
      switch (dir) {
          case 'W':
          case 'w':
              std::cout << "上" << std::endl;
              break;
          case 'S':
          case 's':
              std::cout << "下" << std::endl;
              break;
          case 'A':
          case 'a':
              std::cout << "左" << std::endl;
              break;
          case 'D':
          case 'd':
              std::cout << "右" << std::endl;
              break;
          default:
              std::cout << "无效输入" << std::endl;
              break;
      }
      return 0;
  }

5. 元音辅音判断

  #include <iostream>
  int main() {
      char c;
      std::cin >> c;
      switch (c) {
          case 'a':
          case 'e':
          case 'i':
          case 'o':
          case 'u':
              std::cout << "元音" << std::endl;
              break;
          default:
              std::cout << "辅音" << std::endl;
              break;
      }
      return 0;
  }

11. 相关网络资源推荐

  • cppreference.com - switch statement
  • OI Wiki - 分支结构 (含switch)
  • learncpp.com - Switch statements