分支结构依赖条件判断,条件判断又依赖两类运算符:比较运算符负责比大小,逻辑运算符负责组合多个条件,是学好 if 和 switch 之前必须掌握的基础。
4.1
分支结构依赖条件判断,条件判断又依赖两类运算符:比较运算符用来比较两个值,结果是 true 或 false;逻辑运算符用来把多个简单条件组合成一个更复杂的条件。
| 运算符 | 含义 | 示例 | 结果 | 优先级 |
|---|---|---|---|---|
| > | 大于 | 5 > 3 | true | 6 |
| < | 小于 | 5 < 3 | false | 6 |
| >= | 大于等于 | 5 >= 5 | true | 6 |
| <= | 小于等于 | 3 <= 5 | true | 6 |
| == | 等于(两个等号!) | 5 == 5 | true | 7 |
| != | 不等于 | 5 != 3 | true | 7 |
比较运算符的结果本质上是一个 bool 类型的值(true 或 false),可以直接存进 bool 变量,也可以直接放进 if 的括号里:
| 1 | bool isPass = (85 >= 60); // isPass 存的就是 true |
| 2 | cout << isPass; // 输出 1(C++ 里 true 打印出来是 1,false 是 0) |
| 运算符 | 含义 | 说明 | 示例 | 优先级 |
|---|---|---|---|---|
| && | 且(AND) | 两个条件都为 true 才为 true | age>=6 && age<=12 | 11 |
| || | 或(OR) | 至少一个为 true 就为 true | x==1 || x==2 | 12 |
| ! | 非(NOT) | true 变 false,false 变 true | !(x > 0) | 2 |
== 是比较(两个等号),= 是赋值(一个等号)。写成 if (a = 5) 是赋值不是比较,不会报错但逻辑完全错误,是最难发现的 bug 之一!上面两张表格最后一列的"优先级"数字,代表运算符结合的先后顺序——数字越小,越先被计算。把常用运算符从高到低排一排,能看出一个清晰的规律:
规律是:比较运算符永远比逻辑运算符先算。所以 age >= 6 && age <= 12 不需要额外加括号,编译器会自动先算出两个 >=/<= 的 true/false,再用 && 把结果组合起来。而 && 比 || 优先级更高,意味着 a && b || c && d 会先算两个 &&,再用 || 连接,等价于 (a && b) || (c && d)。
(a && b) || (c && d)。多余的括号不会有任何负面影响,却能让代码意图一目了然,也不用担心自己记错优先级。&& 和 || 有一个非常重要的特性——短路求值:一旦左边的结果已经能确定整个表达式的值,右边就不会再被计算。
| 1 | int a = 0, b = 10; |
| 2 | |
| 3 | if (a != 0 && b / a > 1) // 安全:a!=0 为 false,右边不会执行,不会除零 |
| 4 | { |
| 5 | cout << "b 是 a 的两倍以上"; |
| 6 | } |
&& 是"左边为 false 就短路",|| 是"左边为 true 就短路"——只要 || 左边已经是 true,整个表达式必然是 true,右边同样不会被计算。这个特性常用来把"检查条件是否安全"的判断写在前面,防止后面访问越界、除零等错误。把本节内容汇总成几条最容易踩坑的规则:
if (a = 5) 是把 5 赋值给 a,赋值表达式的结果是 5(非零即真),条件永远成立,编译器通常只给警告不报错,是极难发现的逻辑 bug。写条件判断时养成"字面量写在左边"的习惯(if (5 == a))可以让这类笔误变成编译错误。&& 和 || 的情况。宁可多写几个括号,也不要让别人(包括未来的自己)猜测运算顺序。a != 0 && b / a > 1 这种写法,"检查条件"必须写在前面,"依赖这个条件才安全的操作"写在后面。如果顺序写反成 b / a > 1 && a != 0,除零错误在检查之前就已经发生了。0.1 + 0.2 == 0.3 的结果很可能是 false。判断两个浮点数是否"相等",通常要判断它们的差值是否小于一个很小的阈值,而不是直接用 ==。