第三章 C++ 运算符与表达式
在 C++ 编程中,运算符是用于执行数学或逻辑运算的符号。合理、准确地使用运算符以及理解它们的优先级,是编写高效、无错代码的关键。本章将详细介绍 C++ 中的各类常用运算符、优先级关系、真值表以及类型转换规则。
3.1 运算符优先级及结合性
下表列出了 C++ 中常用运算符的优先级与结合性。优先级从上到下依次递减,同一行中的运算符具有相同的优先级。
| 优先级 | 运算符 | 描述 | 结合方向 |
|---|---|---|---|
| 1 | :: |
作用域解析 | 无 |
| 2 | ., ->, [], () |
成员访问, 指针访问, 数组下标, 函数调用 | 从左向右 |
| 3 | ++, -- (后缀), ++, -- (前缀), !, ~, + (一元), - (一元), * (解引用), & (取地址), (type), sizeof, new, delete |
自增自减, 逻辑非, 按位取反, 正负号, 指针操作, 强转, 内存操作 | 从右向左 |
| 4 | .*, ->* |
成员指针访问 | 从左向右 |
| 5 | *, /, % |
乘法, 除法, 求余(模运算) | 从左向右 |
| 6 | +, - |
加法, 减法 | 从左向右 |
| 7 | <<, >> |
流输入输出, 二进制左移右移 | 从左向右 |
| 8 | <, <=, >, >= |
关系比较 | 从左向右 |
| 9 | ==, != |
等于, 不等于 | 从左向右 |
| 10 | & |
按位与 | 从左向右 |
| 11 | ^ |
按位异或 | 从左向右 |
| 12 | | |
按位或 | 从左向右 |
| 13 | && |
逻辑与 | 从左向右 |
| 14 | || |
逻辑或 | 从左向右 |
| 15 | ?: |
条件运算符(三目运算符) | 从右向左 |
| 16 | =, +=, -=, *=, /=, %=, <<=, >>=, &=, ^=, |= |
赋值与复合赋值 | 从右向左 |
| 17 | , |
逗号运算符 | 从左向右 |
提示:比较运算符、位移运算符、逻辑运算符、条件运算符的优先级较低,使用时建议多加括号,以防出错。
3.2 常用运算符详解与避坑指南
1. 算术运算符
- 基本符号:
+、-、*、/、%分别表示加、减、乘、除、取余。 - 整数除法截断:两个整数做除法时,如果除不开,程序将把小数部分直接截断(不是四舍五入)。即:整数 / 整数 = 整数,浮点数 / 浮点数 = 浮点数。
- 关于乘方:C++ 中没有乘方运算符,
^也不是乘方运算符(^是按位异或)。若要进行乘方运算,需要使用<cmath>头文件中的pow函数。
2. 比较运算符
- 基本符号:
>、>=、<、<=、==(相等)、!=(不等于)。它们用来判断不等关系,返回值是true或false。 - 易错点 1:小心,千万不要把
==写成=! - 易错点 2:永远不要对浮点数使用
==和!=运算符! 正确的做法是自己控制精度。例如:
cpp
const double eps = 0.000001;
if (d >= 2 - eps && d <= 2 + eps) {
// 相当于判断 if (d == 2)
}
- 易错点 3:不应该判断一个变量的值是否等于
true。安全的做法是判断它是否不等于false。例如使用if (flag)或者if (flag != false)。
3. 位运算
- 基本位操作:
&、|、^分别表示按位与、按位或、按位异或,即两个操作数上每一个二进制位都要进行运算。 - 按位求反:
~表示按位求反。 - 二进制位移:
<<、>>表示二进制位的移动。当某一位数字移动到二进制位的外面之后,它就直接“消失”了。 a << n相当于 $a \times 2^n$a >> n相当于 $a \div 2^n$(向下取整)
4. 逻辑与条件运算符
- 基本逻辑操作:
&&、||分别表示与、或。!表示非。 - 条件运算
?::它是 C++ 唯一一个三目运算符,格式为A ? B : C。如果A不为false,那么返回B,否则返回C。可以将这个运算符理解为一个简化版的if。 - 短路特性警告:
||、&&、?:是短路运算符。不要在这三种运算符内调用函数或赋值,以免发生难以查出的错误!
5. 自增(++)与自减(--)运算符
- 基本功能:增量分别是
1和-1。 - 适用对象:这两种运算符只能用于数值类型的变量,不能用于非数值类型变量、常量、表达式和函数调用上。
- 前缀与后缀的区别:前缀运算符返回引用类型,后缀运算符返回数值类型。两者的作用效果不同:
cpp int i = 0, j = 8, k = 5; j = j + (++i); // i先自增,变成1,然后再和j相加。执行之后i=1,j=9。 k = k + (i++); // i先和k相加,使k=6。然后i再自增。执行之后i=2,k=6。 - 避坑指南:为了避免错误,不要让
++、--和其他能够改变变量的操作在同一行出现!
6. 赋值运算符
- 赋值也是运算符:在 C++ 中赋值是一种运算符。所以会看到
i=j=0、d[x=y]、return c=i+j之类的代码。 - 复合赋值:
+=、->=、*=等可以简化书写。例如a *= 2 + 3相当于a = a * (2 + 3)。因为赋值运算符的优先级低于加法。
3.3 逻辑与位运算真值表
| $p$ | $q$ | $p \text{ && } q$ ($p \ \& \ q$) | $p \text{ || } q$ ($p \ | \ q$) | $p \ \hat{} \ q$ | $\text{!}p$ ($\sim p$) | | :---: | :---: | :---: | :---: | :---: | :---: | | true (1) | true (1) | true (1) | true (1) | false (0) | false (0) | | true (1) | false (0) | false (0) | true (1) | true (1) | false (0) | | false (0) | true (1) | false (0) | true (1) | true (1) | true (1) | | false (0) | false (0) | false (0) | false (0) | false (0) | true (1) |
3.4 类型强制转换
用一对小括号把数据类型包上,则它右侧的变量或常量的值(变量本身不变)就变成了对应的类型。如:
int i = 2;
double c = 6.4 / (double)i; // 把i的值变成double类型。
两个操作数进行四则运算,如果想保留小数位,那么两个操作数应该都是浮点数。上面的代码就是这样。
3.5 课后推荐练习题
在掌握了运算符和类型转换之后,建议通过以下几道来自系统题库的练习题进行实战演练:
- 题目编号:10 —— 汽车油耗计算
- 考点:本题要求计算平均油耗。在面对整数与浮点数的混合除法计算时,需要通过类型转换或直接使用浮点数,确保结果的小数部分不被截断。
- 题目编号:13 —— 时间转换
- 考点:读入一个总秒数,通过求模运算
%和除法运算/的配合,依次计算出对应的小时、分钟和秒数。
- 考点:读入一个总秒数,通过求模运算
- 题目编号:16 —— 计算球的体积
- 考点:由于体积公式中含有分数,在 C++ 中若直接书写
4/3会被整除截断为1。必须利用类型强转或实数表达形式(如4/3.0),才能得出正确的浮点数结果。
- 考点:由于体积公式中含有分数,在 C++ 中若直接书写
- 题目编号:20 —— 寻找最大值
- 考点:通过数学公式
(a + b + abs(a - b)) / 2避开条件判断,直接运用基本的算术运算求出最大值,是练习运算符优先级和基础数学函数结合的典型题目。
- 考点:通过数学公式
—— 本文来自火龙信奥(义乌睿码科技):义乌青少年信息学奥赛与编程教育平台,专注 CSP-J/S、NOIP、GESP 竞赛培训,线上线下融合教学,助力编程升学。网址:hlcoding.com