第三章 分支程序设计
关键考点总览
跳转到:关键考点总览- 关系运算符及其优先级
- 逻辑运算符及其优先级
- 短路求值规则
- if语句的两种格式(有/无else)
- if语句的嵌套与else配对原则
- 条件表达式(?:运算符)
- switch语句的格式与执行流程
- break语句在switch中的作用
- 随机数生成(rand/srand)
详细知识点
跳转到:详细知识点3.1 关系表达式
跳转到: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 逻辑表达式
跳转到: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 是否是两位数:
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,测验]
易错点与辨析
跳转到:易错点与辨析- ⚠️ 短路求值导致赋值未执行:
[来源:第3章 p10,逻辑表达式须注意](x = 3) || (b = 4) // x 非零,b 不会被赋值
例题结论
跳转到:例题结论-
【执行结果分析】
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 语句
跳转到:3.3 if 语句定义/语法
跳转到:定义/语法-
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;elsecout << 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语句的嵌套]
3.4 条件表达式
跳转到:3.4 条件表达式定义/语法
跳转到:定义/语法-
条件表达式格式:
(条件) ? 表达式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,例题]
3.5 switch 语句
跳转到:3.5 switch 语句定义/语法
跳转到:定义/语法-
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 的穿透特性):
[来源:第3章 p22,将百分制成绩转换成5级记分制]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";}
易错点与辨析
跳转到:易错点与辨析-
⚠️ 错误写法:case 后使用变量或关系表达式
// 错误!case 后必须是常量case score >= 90: cout << "A"; break;[来源:第3章 p21,将百分制成绩转换成5级记分制]
-
⚠️ 忘记 break 会导致所有后续 case 都被执行
[来源:第3章 p20,Notes]
3.6 随机数生成
跳转到:3.6 随机数生成定义/语法
跳转到:定义/语法-
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)本章主要介绍了计算机实现逻辑思维的机制,包括两个方面:
-
如何表示一个逻辑判断:
- 关系表达式
- 逻辑表达式
- ⚠️ 需熟练掌握!
-
如何根据逻辑判断的结果执行不同的处理:
- if 语句
- switch 语句
[来源:第3章 p27,总结;p27 Notes]