# 第三章 分支程序设计

> Arietids Learn · 个人课程复习笔记
> 在线阅读：https://learn.arietids.net/courses/programming/chapter-03/

## 关键考点总览

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

---

## 详细知识点

### 3.1 关系表达式

#### 定义/语法

- **关系运算**：比较两个表达式的结果（如大小、是否相等）  
  [来源：第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，示例]

---

### 3.2 逻辑表达式

#### 定义/语法

- **逻辑运算**：对一个或两个操作数进行逻辑运算（操作数先转换为 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 是否是两位数**：
  ```cpp
  m > 9 && m < 100
  ```
  [来源：第3章 p9，测验]

- **判断字符变量 a 是否为字母**：
  ```cpp
  a >= 'a' && a <= 'z' || a >= 'A' && a <= 'Z'
  ```
  （无需记编码数值；直接用字符字面量区间比较即可。65/90/97/122 仅在 ASCII/UTF-8 等编码中成立）  
  [来源：第3章 p9，测验；p9 Notes]

- **判断整型变量 m 是否为奇数**：
  ```cpp
  m % 2 != 0
  ```
  [来源：第3章 p9，测验]

- **x 不等于 2 或 3**（两种等价写法）：
  ```cpp
  x != 2 && x != 3
  !(x == 2 || x == 3)
  ```
  [来源：第3章 p9，测验]

#### 易错点与辨析

- ⚠️ **短路求值导致赋值未执行**：
  ```cpp
  (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]

---

### 3.3 if 语句

#### 定义/语法

- **if 语句格式1**（无 else）：
  ```cpp
  if (条件测试) 语句
  ```
  [来源：第3章 p12，if语句]

- **if 语句格式2**（有 else）：
  ```cpp
  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 结构**：
  ```cpp
  if (grade >= 60) {
      cout << "passed" << endl;
      cout << "Congrats!" << endl;
  } else {
      cout << "failed" << endl;
      cout << "Sorry!" << endl;
  }
  ```
  [来源：第3章 p12，if语句]

- **判断闰年**：
  ```cpp
  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 配对：
  ```cpp
  if (x < 100)  if (x < 90)  语句1  else  语句2
  // else 与内层 if (x < 90) 配对
  ```
  [来源：第3章 p14，if语句的嵌套]

---

### 3.4 条件表达式

#### 定义/语法

- **条件表达式格式**：
  ```cpp
  (条件) ? 表达式1 : 表达式2
  ```
  [来源：第3章 p16，条件表达式]

- **问号冒号运算符**：`?:`  
  [来源：第3章 p16，条件表达式]

#### 执行逻辑

- 首先计算条件值；如果条件结果为 true，则计算表达式1的值，并将它作为整个表达式的值；如果条件结果为 false，则整个表达式的值为表达式2的值  
  [来源：第3章 p16，条件表达式]

#### 代码模式

- **将 x 和 y 中值较大的一个赋值给 max**：
  ```cpp
  max = (x > y) ? x : y;
  ```
  [来源：第3章 p16，条件表达式]

- **求变量 m 的绝对值**：
  ```cpp
  (m > 0) ? m : -m
  ```
  [来源：第3章 p17，例题]

- **输出学生补考成绩是否通过**：
  ```cpp
  cout << (s >= 60 ? "passed" : "failed");
  ```
  [来源：第3章 p17，例题]

---

### 3.5 switch 语句

#### 定义/语法

- **switch 语句格式**：
  ```cpp
  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  
  ```cpp
  switch (表达式) {
      case 整型常量表达式1: 语句1; break;
      case 整型常量表达式2: 语句2; break;
      ...
      default: 语句n+1;
  }
  ```
  [来源：第3章 p20，break语句]

#### 代码模式

- **多个 case 执行相同语句**（利用无 break 的穿透特性）：
  ```cpp
  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 后使用变量或关系表达式
  ```cpp
  // 错误！case 后必须是常量
  case score >= 90: cout << "A"; break;
  ```
  [来源：第3章 p21，将百分制成绩转换成5级记分制]

- ⚠️ **忘记 break 会导致所有后续 case 都被执行**  
  [来源：第3章 p20，Notes]

---

### 3.6 随机数生成

#### 定义/语法

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

- **伪随机数序列**：看似随机，实际有规律可循的序列  
  [来源：第3章 p24，随机数的生成]

- **srand()**：设置随机数种子  
  [来源：第3章 p24，随机数的生成]

- **time(nullptr)**：返回当前系统时间戳（秒）；常用作随机数种子  
  [来源：第3章 p24，随机数的生成]

#### 规则/规范

- 给定相同的随机数种子，每次生成的随机数序列**相同**  
  [来源：第3章 p24，随机数的生成]

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

#### 代码模式

- **生成 0-9 之间的随机数**：
  ```cpp
  rand() % 10
  ```
  [来源：第3章 p23，计算机自动出四则运算计算题]

- **另一种方法**（需注意边界/溢出问题）：
  ```cpp
  static_cast<int>((static_cast<long long>(rand()) * 10) / (static_cast<long long>(RAND_MAX) + 1))
  ```
  [来源：第3章 p23，计算机自动出四则运算计算题]

- **初始化随机数种子**：
  ```cpp
  #include <cstdlib>  // 包含伪随机数生成函数
  #include <ctime>    // 包含取系统时间的函数
  
  srand(static_cast<unsigned>(time(nullptr)));  // 随机数种子初始化（通常只需调用一次）
  ```
  [来源：第3章 p25，计算机自动出四则运算计算题]

---

## 本章总结（来源：第3章 p27）

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

1. **如何表示一个逻辑判断**：
   - 关系表达式
   - 逻辑表达式
   - ⚠️ **需熟练掌握！**

2. **如何根据逻辑判断的结果执行不同的处理**：
   - if 语句
   - switch 语句

[来源：第3章 p27，总结；p27 Notes]
