跳转到内容

第三章 分支程序设计

  1. 关系运算符及其优先级
  2. 逻辑运算符及其优先级
  3. 短路求值规则
  4. if语句的两种格式(有/无else)
  5. if语句的嵌套与else配对原则
  6. 条件表达式(?:运算符)
  7. switch语句的格式与执行流程
  8. break语句在switch中的作用
  9. 随机数生成(rand/srand)

  • 关系运算:比较两个表达式的结果(如大小、是否相等)
    [来源:第3章 p6,关系表达式]

  • 关系表达式的结果:返回 bool(true / false);在需要数值时通常表现为 1 / 0
    [来源:第3章 p6,关系表达式]

  • 关系运算符:>,>=,==,<=,<,!=
    [来源:第3章 p6,关系表达式]

  • 优先级:关系/相等运算符低于算术运算符(+ - * / %)及移位运算符(<< >>),高于赋值运算符
    [来源:第3章 p6,关系表达式]

  • 内部优先级:== 和 != 的优先级较低(低于 >、>=、<、<=)
    [来源:第3章 p6,关系表达式]

  • 结合性:关系运算遵循左结合原则
    [来源:第3章 p6,Notes]

  • ⚠️ 连续比较陷阱:9<m<100 不能用于判断 m 是两位数!
    • 实际执行:(9<m)<100,即先算 9<m 得到 0 或 1,再与 100 比较,结果恒为 true
    • 正确写法:m>9 && m<100
      [来源:第3章 p9,测验;p9 Notes]
  • 【执行结果分析】 3 == 3 > 0 的值为 0(false)

    • 执行顺序:先算 3 > 0 得 1,再算 3 == 1 得 0
      [来源:第3章 p6,示例]
  • 【执行结果分析】 5 + 3 > 6 - 2 的值为 1(true)

    • 执行顺序:先算 5+3=8 和 6-2=4,再比较 8 > 4
      [来源:第3章 p6,示例]

  • 逻辑运算:对一个或两个操作数进行逻辑运算(操作数先转换为 bool),得到一个逻辑结果
    [来源:第3章 p8,逻辑表达式]

  • 逻辑运算的操作对象:布尔型(非布尔型时:0 为假,非0 为真)
    [来源:第3章 p8,逻辑表达式]

  • 逻辑运算的结果:返回 bool(true / false);在需要数值时通常表现为 1 / 0
    [来源:第3章 p8,逻辑表达式]

  • 逻辑运算符:&&(与)、||(或)、!(非)
    [来源:第3章 p8,逻辑表达式]

  • 优先级顺序(从高到低):! > 关系运算符 > && > ||
    [来源:第3章 p8,逻辑表达式]

  • 短路求值:逻辑表达式执行时,先处理左边,如左边已能决定整个表达式的结果,则右边不执行
    [来源:第3章 p10,逻辑表达式须注意]

  • 尽量避免在关系/逻辑表达式中写赋值(除非明确需要其副作用);否则容易把 = 误写成 ==,且可能被短路规则跳过
    [来源:第3章 p8,逻辑表达式]

  • 优化建议:

    • 在 && 表达式中,应把 false 可能性较大的条件放在左边
    • 在 || 表达式中,应把 true 可能性较大的条件放在左边
      [来源:第3章 p10,逻辑表达式须注意]
  • 判断整型变量 m 是否是两位数:

    m > 9 && m < 100

    [来源:第3章 p9,测验]

  • 判断字符变量 a 是否为字母:

    a >= 'a' && a <= 'z' || a >= 'A' && a <= 'Z'

    (无需记编码数值;直接用字符字面量区间比较即可。65/90/97/122 仅在 ASCII/UTF-8 等编码中成立)
    [来源:第3章 p9,测验;p9 Notes]

  • 判断整型变量 m 是否为奇数:

    m % 2 != 0

    [来源:第3章 p9,测验]

  • x 不等于 2 或 3(两种等价写法):

    x != 2 && x != 3
    !(x == 2 || x == 3)

    [来源:第3章 p9,测验]

  • ⚠️ 短路求值导致赋值未执行:
    (x = 3) || (b = 4) // x 非零,b 不会被赋值
    [来源:第3章 p10,逻辑表达式须注意]
  • 【执行结果分析】 5 > 3 && 2 || 8 < 4 的值为 1

    • 执行顺序:(5>3)=1 → 1 && 2 = 1 → 1 || (8<4) = 1
      [来源:第3章 p8,示例]
  • 【执行结果分析】 已知 a=1, b=2, c=2, d=4, m=1, n=1,执行 (m = a > b) && (n = c > d) 后,m 和 n 的值分别为?

    • 结果:m = 0,n = 1(n 保持原值,因短路求值未执行右侧)
    • 分析:a > b 为 0,赋给 m;左侧为 0,整个 && 已确定为假,右侧不执行
      [来源:第3章 p10,逻辑表达式须注意;p10 Notes]

  • if 语句格式1(无 else):

    if (条件测试) 语句

    [来源:第3章 p12,if语句]

  • if 语句格式2(有 else):

    if (条件测试) 语句1 else 语句2

    [来源:第3章 p12,if语句]

  • then 子句:条件测试为 true(非零)时执行的程序块
    else 子句:条件测试为 false(零)时执行的程序块
    [来源:第3章 p12,if语句]

  • 程序块:可以是一行语句,也可以是由大括号括起来的多行语句
    [来源:第3章 p12,Notes]

  • 条件测试内容:条件会被“上下文转换”为 bool;常见写法是关系/逻辑表达式。语法上也允许算术或赋值表达式,但不推荐把赋值当条件(除非非常明确)
    [来源:第3章 p12,Notes]

  • if-else 配对原则:遵循临近原则,else 与最近的 if 配对
    [来源:第3章 p14,if语句的嵌套;p14 Notes]

  • 缩进规范:善用缩进可以清晰地表示层次,便于程序员阅读(虽然 C++ 不关心格式)
    [来源:第3章 p15,缩进对齐]

  • 基本 if-else 结构:

    if (grade >= 60) {
    cout << "passed" << endl;
    cout << "Congrats!" << endl;
    } else {
    cout << "failed" << endl;
    cout << "Sorry!" << endl;
    }

    [来源:第3章 p12,if语句]

  • 判断闰年:

    result = (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
    if (result)
    cout << year << "是闰年" << endl;
    else
    cout << year << "不是闰年" << endl;

    (规则:4年一闰,百年不闰,四百年闰)
    [来源:第3章 p13,判断闰年的程序]

  • ⚠️ 容易犯的错误:把赋值 = 当成等号 == 用
    [来源:第3章 p12,Notes]

  • ⚠️ 嵌套 if 时,若不用大括号,else 与最近的 if 配对:

    if (x < 100) if (x < 90) 语句1 else 语句2
    // else 与内层 if (x < 90) 配对

    [来源:第3章 p14,if语句的嵌套]


  • 条件表达式格式:

    (条件) ? 表达式1 : 表达式2

    [来源:第3章 p16,条件表达式]

  • 问号冒号运算符:?:
    [来源:第3章 p16,条件表达式]

  • 首先计算条件值;如果条件结果为 true,则计算表达式1的值,并将它作为整个表达式的值;如果条件结果为 false,则整个表达式的值为表达式2的值
    [来源:第3章 p16,条件表达式]
  • 将 x 和 y 中值较大的一个赋值给 max:

    max = (x > y) ? x : y;

    [来源:第3章 p16,条件表达式]

  • 求变量 m 的绝对值:

    (m > 0) ? m : -m

    [来源:第3章 p17,例题]

  • 输出学生补考成绩是否通过:

    cout << (s >= 60 ? "passed" : "failed");

    [来源:第3章 p17,例题]


  • switch 语句格式:

    switch (表达式) {
    case 整型常量表达式1: 语句1;
    case 整型常量表达式2: 语句2;
    ...
    case 整型常量表达式n: 语句n;
    default: 语句n+1;
    }

    [来源:第3章 p19,switch语句]

  • default 子句可以省略:当表达式的值不等于任何 case 值时,直接跳出 switch 语句
    [来源:第3章 p19,switch语句]

  • 当 switch 表达式的值等于某个 case 标签常量时,从该 case 处开始执行;若缺少 break 会继续贯穿到后续 case/default,直到遇到 break / return / throw 或到达 switch 末尾
    [来源:第3章 p19,switch语句]

  • 若没有任何 case 匹配:有 default 就从 default 开始执行;没有 default 就直接跳到 switch 末尾
    [来源:第3章 p19,switch语句]

  • case 标签必须是整型/枚举的“常量表达式”(可用字面量、枚举值、const/constexpr 整型常量等);不能是运行期变量或关系表达式
    [来源:第3章 p21,Notes]

  • break 语句:用于从语句体中跳出,防止执行后续 case

    switch (表达式) {
    case 整型常量表达式1: 语句1; break;
    case 整型常量表达式2: 语句2; break;
    ...
    default: 语句n+1;
    }

    [来源:第3章 p20,break语句]

  • 多个 case 执行相同语句(利用无 break 的穿透特性):
    switch (score / 10) {
    case 10:
    case 9: cout << "A"; break;
    case 8: cout << "B"; break;
    case 7: cout << "C"; break;
    case 6: cout << "D"; break;
    default: cout << "E";
    }
    [来源:第3章 p22,将百分制成绩转换成5级记分制]
  • ⚠️ 错误写法:case 后使用变量或关系表达式

    // 错误!case 后必须是常量
    case score >= 90: cout << "A"; break;

    [来源:第3章 p21,将百分制成绩转换成5级记分制]

  • ⚠️ 忘记 break 会导致所有后续 case 都被执行
    [来源:第3章 p20,Notes]


  • rand():生成 [0, RAND_MAX] 之间的伪随机整数(包含两端)
    [来源:第3章 p23,计算机自动出四则运算计算题]

  • 伪随机数序列:看似随机,实际有规律可循的序列
    [来源:第3章 p24,随机数的生成]

  • srand():设置随机数种子
    [来源:第3章 p24,随机数的生成]

  • time(nullptr):返回当前系统时间戳(秒);常用作随机数种子
    [来源:第3章 p24,随机数的生成]

  • 给定相同的随机数种子,每次生成的随机数序列相同
    [来源:第3章 p24,随机数的生成]

  • 使用系统时间作为种子可让每次运行生成不同的随机数序列
    [来源:第3章 p24,随机数的生成]

  • 生成 0-9 之间的随机数:

    rand() % 10

    [来源:第3章 p23,计算机自动出四则运算计算题]

  • 另一种方法(需注意边界/溢出问题):

    static_cast<int>((static_cast<long long>(rand()) * 10) / (static_cast<long long>(RAND_MAX) + 1))

    [来源:第3章 p23,计算机自动出四则运算计算题]

  • 初始化随机数种子:

    #include <cstdlib> // 包含伪随机数生成函数
    #include <ctime> // 包含取系统时间的函数
    srand(static_cast<unsigned>(time(nullptr))); // 随机数种子初始化(通常只需调用一次)

    [来源:第3章 p25,计算机自动出四则运算计算题]


本章总结(来源:第3章 p27)

跳转到:本章总结(来源:第3章 p27)

本章主要介绍了计算机实现逻辑思维的机制,包括两个方面:

  1. 如何表示一个逻辑判断:

    • 关系表达式
    • 逻辑表达式
    • ⚠️ 需熟练掌握!
  2. 如何根据逻辑判断的结果执行不同的处理:

    • if 语句
    • switch 语句

[来源:第3章 p27,总结;p27 Notes]