159 lines
8.4 KiB
Markdown
159 lines
8.4 KiB
Markdown
# 逻辑运算符
|
||
|
||
### 1. 引言
|
||
|
||
* **问题引入**:
|
||
妈妈许诺说:“如果你这次数学考到90分,**并且**英语也考到90分,我就给你买新的游戏机!”
|
||
这里的关键是“**并且**”,它意味着两个条件必须**同时**满足。
|
||
后来妈妈看你压力太大了,又说:好吧,要求降低一点。只要你数学考到90分,**或者**英语考到90分,我就带你去吃大餐!
|
||
这里的关键是“**或者**”,它意味着两个条件只要满足**任意一个**就行。
|
||
在C++中,我们如何表达这种“并且”、“或者”的复杂逻辑呢?
|
||
|
||
* **价值阐述**:逻辑运算符是构建程序决策的核心。它让我们可以将简单的判断 (`a > b`, `c == 0`) 组合成复杂的逻辑规则。从网站的用户登录(用户名**和**密码都正确)、游戏胜利条件(敌人数量为0**或**到达终点)、到复杂的AI决策,逻辑运算符无处不在。
|
||
|
||
* **学习目标**:
|
||
1. 掌握 C++ 的三个逻辑运算符:`&&` (与), `||` (或), `!` (非)。
|
||
2. 理解并能口述每个运算符的运算规则。
|
||
3. 掌握“短路求值”这一重要特性,并理解其意义。
|
||
4. 了解逻辑运算符、关系运算符和算术运算符之间的优先级关系。
|
||
|
||
### 2. 核心思想
|
||
|
||
* **思路铺垫**:
|
||
我们已经知道,关系运算符(如 `>`、`==`)的运算结果是一个 `bool` 值(`true` 或 `false`)。逻辑运算符不做数值计算,它的工作对象就是这些 `bool` 值。它根据输入的 `true` 或 `false`,给出一个最终的 `true` 或 `false` 结果。
|
||
|
||
* **算法精讲**:
|
||
C++ 主要有三个逻辑运算符,我们用来一一拆解。
|
||
1. **逻辑与 `&&` (AND)**
|
||
* **含义**:表示“并且”,要求左右两边的条件**都**为 `true` 时,最终结果才是 `true`。只要有一个是 `false`,结果就是 `false`。
|
||
* **生活实例**:`数学 >= 90 && 英语 >= 90`。
|
||
* **规则表 (真值表)**:
|
||
| A | B | A && B |
|
||
| :---: | :---: | :----: |
|
||
| `true` | `true` | `true` |
|
||
| `true` | `false`| `false`|
|
||
| `false`| `true` | `false`|
|
||
| `false`| `false`| `false`|
|
||
* **记忆口诀**:**全真才为真,一假即为假。**
|
||
|
||
2. **逻辑或 `||` (OR)**
|
||
含义**:表示“或者”,只要左右两边的条件有**任意一个**为 `true`,最终结果就是 `true`。只有当两个都为 `false` 时,结果才是 `false`。
|
||
生活实例**:`数学 >= 90 || 英语 >= 90`。
|
||
**规则表 (真值表)**:
|
||
| A | B | A \|\| B |
|
||
| :---: | :---: | :----: |
|
||
| `true` | `true` | `true` |
|
||
| `true` | `false`| `true` |
|
||
| `false`| `true` | `true` |
|
||
| `false`| `false`| `false`|
|
||
* **记忆口诀**:**一真即为真,全假才为假。**
|
||
|
||
3. **逻辑非 `!` (NOT)**
|
||
|
||
**含义**:表示“取反”,它是一个单目运算符(只有一个操作数)。它会把 `true` 变成 `false`,把 `false` 变成 `true`。
|
||
|
||
**生活实例**:妈妈说:“只要你数学**不**低于70分就有奖励”。“不低于70分”等价于 `!(数学 < 70)`。
|
||
|
||
**规则表 (真值表)**:
|
||
| A | !A |
|
||
| :---: | :----: |
|
||
| `true` | `false`|
|
||
| `false`| `true` |
|
||
* **记忆口诀**:**真变假,假变真。**
|
||
|
||
* **步骤拆解 (特性:短路求值)**
|
||
计算机其实很聪明,它会用最快的方式得到逻辑运算的结果。
|
||
|
||
* **对于 `&&` (与)**:`条件A && 条件B`
|
||
1. 计算机先计算 `条件A`。
|
||
2. 如果 `条件A` 的结果是 `false`,它会想:“根据‘一假即为假’的规则,无论 `条件B` 是什么,最终结果肯定是 `false` 了。”
|
||
3. 于是,计算机**直接返回 `false`,根本不会去计算 `条件B`**。这个行为就叫“短路”。
|
||
* **回到例子**:如果你的数学考了88分 (`math >= 90` 为 `false`),计算机根本不需要再看你的英语成绩,就知道你拿不到游戏机了。
|
||
|
||
* **对于 `||` (或)**:`条件A || 条件B`
|
||
|
||
1. 计算机先计算 `条件A`。
|
||
2. 如果 `条件A` 的结果是 `true`,它会想:“根据‘一真即为真’的规则,无论 `条件B` 是什么,最终结果肯定是 `true` 了。”
|
||
3. 于是,计算机**直接返回 `true`,根本不会去计算 `条件B`**。
|
||
* **回到例子**:如果你的数学考了100分 (`math >= 90` 为 `true`),计算机根本不需要再看你的英语成绩,就知道你已经有大餐吃了。
|
||
|
||
### 3. 实例
|
||
|
||
* **具体案例**:
|
||
假设 `int score = 85;`,我们来分析表达式 `score > 80 && score < 90` 的真假。
|
||
* **分步演示**:
|
||
1. **拆分表达式**:这个逻辑表达式由两个关系表达式 `score > 80` 和 `score < 90`,以及一个逻辑运算符 `&&` 组成。
|
||
2. **计算左侧**:`score > 80` -> `85 > 80` -> 结果为 `true`。
|
||
3. **判断短路**:因为是 `&&` 运算,左侧为 `true` 还不能确定最终结果,所以**不能短路**,必须继续计算右侧。
|
||
4. **计算右侧**:`score < 90` -> `85 < 90` -> 结果为 `true`。
|
||
5. **最终结果**:`true && true` -> 根据 `&&` 的规则,最终结果为 `true`。
|
||
|
||
### 4. 代码实现
|
||
|
||
* **问题**:输入一个学生的数学和英语成绩,判断他是否能拿到游戏机(两门都>=90),是否能吃到大餐(任意一门>=90)。
|
||
|
||
* **完整代码**:
|
||
```cpp
|
||
#include <iostream>
|
||
using namespace std;
|
||
|
||
int main() {
|
||
int math_score, english_score;
|
||
cout << "请输入数学成绩和英语成绩: ";
|
||
cin >> math_score >> english_score;
|
||
|
||
// 判断是否能拿到游戏机 (&&)
|
||
bool can_get_game = (math_score >= 90) && (english_score >= 90);
|
||
|
||
// 判断是否能吃到大餐 (||)
|
||
bool can_get_dinner = (math_score >= 90) || (english_score >= 90);
|
||
|
||
// (了解即可)C++中,boolalpha 可以让我们直接输出 true 或 false 而不是被计算机转化的 0 和 1
|
||
// 如果不添加下面这一行 cout << boolalpha; 那么输出 true 或 false 就会被计算机转为 1 和 0
|
||
cout << boolalpha;
|
||
|
||
cout << "能拿到游戏机吗? " << can_get_game << endl;
|
||
cout << "能吃到大餐吗? " << can_get_dinner << endl;
|
||
|
||
return 0;
|
||
}
|
||
```
|
||
|
||
* **代码解读**:
|
||
* `bool can_get_game = (math_score >= 90) && (english_score >= 90);`
|
||
* 我们把整个逻辑表达式的结果存入一个 `bool` 类型的变量 `can_get_game`。
|
||
* 括号 `()` 的使用让代码的可读性变得非常好,我们一眼就能看出是在对两个条件进行 `&&` 操作。
|
||
* `cout << boolalpha;`
|
||
* 这是一个输出格式控制器。加上它之后,`cout` 在打印 `bool` 值时,会打印出 "true" 或 "false" ,而不是 "1" 或 "0",这样结果更直观。
|
||
|
||
### 5. 深化
|
||
* **运算符优先级**
|
||
当一个复杂的表达式里什么运算符都有的时候,计算顺序是怎样的?
|
||
**口诀:==非算关与或==** (`非` > `算术` > `关系` > `与` > `或`)
|
||
|
||
1. **最高**:`!` (逻辑非) 和 `()` (括号)
|
||
2. **次高**:算术运算符 (`*`, `/`, `+`, `-`)
|
||
3. **中等**:关系运算符 (`>`, `<`, `==`, `!=`)
|
||
4. **次低**:`&&` (逻辑与)
|
||
5. **最低**:`||` (逻辑或)
|
||
|
||
**黄金法则**:如果你不确定优先级,或者想让代码意图更清晰,**那就毫不犹豫地使用括号 `()`**!例如 `(a + b > 5) && (c == 0)`。
|
||
|
||
* **常见问题**:
|
||
|
||
1. **`0 || 0` 的结果是什么?**
|
||
* 我们知道“非零即为真”,所以 `0` 在逻辑判断中被当作 `false`。
|
||
* 表达式相当于 `false || false`。根据 `||` 的“全假才为假”规则,结果为 `false` (会输出 0)。
|
||
2. `!(-3)` 的结果是什么?
|
||
* `-3` 是一个非零数,所以它被当作 `true`。
|
||
* 表达式相当于 `!(true)`。根据 `!` 的取反规则,结果为 `false` (会输出 0)。
|
||
|
||
### 6. 总结
|
||
|
||
* **要点回顾**:
|
||
1. **逻辑与 `&&`**:全真才为真。左侧为假时发生短路。
|
||
2. **逻辑或 `||`**:一真即为真。左侧为真时发生短路。
|
||
3. **逻辑非 `!`**:取反,真变假,假变真。
|
||
4. **优先级**:`!` > 算术 > 关系 > `&&` > `||`。**括号是王道**,**口诀:非算关与或**。
|
||
5. **短路求值**:一种优化策略,可以避免不必要的计算。
|