C++ 运算符

在编写程序时,我们经常需要对数据进行计算或判断。在 C++ 中,用来对变量或具体数值执行运算操作的符号就叫做 “运算符”。比如在 score + 5 中,+ 是运算符,而参与运算的 score 和 5 则叫做 “操作数”。

由运算符和操作数组合起来、计算后能够产生一个结果的代码片段,称为 “表达式”,比如 score + 5、age >= 18。在日常开发中,最常用的 C++ 运算符主要有以下 5 类:

  • 算术运算符:用来完成加、减、乘、除、求余等数学计算。
  • 自增与自减运算符:用来让变量在原值的基础上加 1 或减 1。
  • 赋值运算符:用来把等号右边的值保存到左边的变量中。
  • 比较运算符:用来比较两个值的大小或是否相等,结果为布尔值。
  • 逻辑运算符:用来把多个条件组合起来进行真假判断。

C++ 算术运算符

在 C++ 中,算术运算符主要用于日常的数学计算,包括加、减、乘、除和求余。常用的算术运算符如下表所示。

算术运算符
运算符 说明 示例 结果
+ 加 10 + 4 14
- 减 10 - 4 6
* 乘 10 * 4 40
/ 除 10 / 4 2
% 求余(取模) 10 % 4 2

注意 在 C++ 中,乘号写作星号(*)而不是 ×,除号写作斜杠(/)而不是 ÷。这是因为键盘上没有专门的 × 和 ÷ 按键,编程语言统一使用键盘上现成的符号来表示乘除。

1. 加、减、乘、除运算

加(+)、减(-)、乘(*)与平时的数学计算完全一致,最需要我们留意的是除法(/):如果除号两边都是整数,执行的就是 “整数除法”,结果只保留整数部分并直接舍去小数。只有当至少有一边是浮点数时,算出的结果才是浮点数。

示例 1:整型的加减乘除

#include <iostream>

int main() {
    int a = 10;
    int b = 4;

    std::cout << a + b << '\n';
    std::cout << a - b << '\n';
    std::cout << a * b << '\n';
    std::cout << a / b << '\n';
    return 0;
}

运行结果如下。

14
6
40
2

分析:

前三个算式 a + b、a - b、a * b 分别计算出 14、6 和 40。需要小伙伴们重点留意的是第四行 a / b:按平时的数学计算,10 除以 4 等于 2.5,但这里输出的却是 2。

这是因为变量 a 和 b 都是 int 整型。在 C++ 中,两个整数相除得到的依然是整数。如果商带有小数,程序不会四舍五入,而是直接抹去小数部分,所以 10 / 4 的结果是 2,同理 3 / 4 的结果会直接变成 0。

那如果我们希望除法保留小数部分,算出准确的 2.5,应该怎么写呢?下面我们再来看一个例子。

示例 2:浮点数的除法运算

#include <iostream>

int main() {
    double x = 10.0;
    int b = 4;
    std::cout << x / b << '\n';
    return 0;
}

运行结果如下。

2.5

分析:

在这个例子中,x 是 double 类型,b 是 int 类型。对于加、减、乘、除运算,只要参与运算的两个数中有一个是浮点型,最终结果就是浮点数,因此 x / b 算出了 2.5。

需要注意的是,如果除号两边写的都是整数字面量,比如 10 / 4,程序会先按整数除法算出 2,哪怕再赋给 double 变量也只会变成 2.0。要想保留小数,至少要将其中一个数字写成小数形式,比如写成 10.0 / 4。如果除号两边原本就是两个 int 变量,则可以借助类型转换先把其中一个转为 double。

2. 求余运算(%)

% 叫做求余运算符(也叫取模运算符),用来求两个整数相除之后的余数。求余运算在实际开发中经常用到,比如判断一个数能不能整除另一个数,或者通过看 n % 2 是否等于 0 来判断奇偶数。

示例 3:整数求余运算

#include <iostream>

int main() {
    int a = 10;
    int b = 4;
    std::cout << a % b << '\n';
    return 0;
}

运行结果如下。

2

分析:

a % b 表示计算 10 除以 4 的余数:10 除以 4 的商是 2,余数是 2,因此输出 2。如果参与求余的数包含负数,余数的正负号始终与左边的被除数保持一致,比如 -10 % 4 的结果是 -2,而 10 % -4 的结果是 2。

使用求余运算符时还要记住两条硬性规则:第一,% 两边的操作数都必须是整数,不能对小数求余,否则会直接编译报错。第二,除法(/)和求余(%)右边的除数不能为 0,否则会导致程序运行出错或直接崩溃。

自增与自减运算符

平时写代码时,我们经常需要让一个变量在原值的基础上加 1 或减 1,C++ 专门提供了自增运算符(++)和自减运算符(--)来简化这种操作。

语法:

++变量名;    // 前置自增
变量名++;    // 后置自增

--变量名;    // 前置自减
变量名--;    // 后置自减

说明:

无论是前置形式还是后置形式,++ 都会让变量自身的值加 1,-- 都会让变量自身的值减 1。如果只是把 a++; 或 ++a; 单独写成一行语句,它们的效果完全一样。

但如果把它们放进赋值或输出等其他表达式中,前置和后置的执行先后顺序就不一样了,下面我们分开来看。

1. 自增运算符(++)

自增运算符分为前置自增(++a)和后置自增(a++)两种形式。

示例 4:前置自增

#include <iostream>

int main() {
    int a = 10;
    int b = ++a;

    std::cout << a << '\n';
    std::cout << b << '\n';
    return 0;
}

运行结果如下。

11
11

分析:

++a 表示 “先自增,后使用”。也就是说,在把 a 的值赋给 b 之前,先让 a 自身加上 1。对于这个例子来说,上面代码等价于下面两步:

int a = 10;
a = a + 1;    // a 先加 1 变成 11
int b = a;    // 再赋给 b,b 也是 11

示例 5:后置自增

#include <iostream>

int main() {
    int a = 10;
    int b = a++;

    std::cout << a << '\n';
    std::cout << b << '\n';
    return 0;
}

运行结果如下。

11
10

分析:

a++ 表示 “先使用,后自增”。也就是说,先拿 a 原来的旧值 10 赋给 b,等赋值完成后,再让 a 自身加上 1。对于这个例子来说,上面代码等价于下面两步:

int a = 10;
int b = a;    // 先把旧值 10 赋给 b
a = a + 1;    // a 再加 1 变成 11

区分 b = ++a; 和 b = a++; 时,小伙伴们只需要记住一个很直观的规律:谁写在前面,就先执行谁。++ 在前面(++a),就先加 1 再取值。a 在前面(a++),就先取出 a 的旧值参与运算,最后再加 1。

2. 自减运算符(--)

自减运算符表示在原值基础上减去 1,运算规则与自增运算符完全相同,同样分为前置自减(--a)和后置自减(a--)。

示例 6:前置与后置自减

#include <iostream>

int main() {
    int a = 10;
    int x = --a;

    int b = 10;
    int y = b--;

    std::cout << a << ' ' << x << '\n';
    std::cout << b << ' ' << y << '\n';
    return 0;
}

运行结果如下。

9 9
9 10

分析:

第一组 int x = --a; 是前置自减,a 先减 1 变成 9,再赋给 x,因此 a 和 x 都是 9。第二组 int y = b--; 是后置自减,先把 b 的旧值 10 赋给 y,随后 b 自己再减 1 变成 9,因此第二行输出 9 10。

C++ 赋值运算符

在 C++ 中,赋值运算符用来把右边的值或表达式计算结果保存到左边的变量中。除了最基本的 = 之外,C++ 还提供了一系列复合赋值运算符,如下表所示。

常用赋值运算符
运算符 说明 示例 等价写法
= 基本赋值 a = 10 将 10 赋值给变量 a
+= 加后赋值 a += b a = a + b
-= 减后赋值 a -= b a = a - b
*= 乘后赋值 a *= b a = a * b
/= 除后赋值 a /= b a = a / b
%= 求余后赋值 a %= b a = a % b

像 a += b 其实就是 a = a + b 的简写形式,这类复合赋值运算符在实际项目代码中非常常用。

示例 7:使用复合赋值运算符

#include <iostream>

int main() {
    int score = 60;
    score += 10;
    score *= 2;
    std::cout << score << '\n';
    return 0;
}

运行结果如下。

140

分析:

在这个例子中,score += 10; 等价于 score = score + 10;,执行后 score 从 60 变成 70。接着执行 score *= 2;,等价于 score = score * 2;,因此最终输出结果为 140。

这里有一个细节值得大家留意:如果复合赋值运算符右边是一个算式,比如 n *= 2 + 1;,程序会先把右边的 2 + 1 整体算完得到 3,再与左边的 n 相乘。也就是说,n *= 2 + 1; 等价于 n = n * (2 + 1);,而不是 n * 2 + 1。

C++ 比较运算符

在 C++ 中,比较运算符(也叫关系运算符)用来比较两个值的大小或是否相等。比较完成之后,得到的结果是一个 bool 布尔值:条件成立为 true,不成立为 false,在编写 if...else 语句时会大量用到。常用的比较运算符如下表所示。

比较运算符
运算符 说明 示例 结果
> 大于 20 > 10 true
< 小于 20 < 10 false
>= 大于或等于 20 >= 20 true
<= 小于或等于 20 <= 10 false
== 等于 20 == 20 true
!= 不等于 20 != 20 false

需要注意的是,由两个字符组成的比较运算符(>=、<=、==、!=)是一个整体,两个符号中间不能留空格,比如不能拆写成 > = 或 = =,否则会直接编译报错。

示例 8:使用比较运算符

#include <iostream>

int main() {
    int age = 20;
    bool isAdult = (age >= 18);
    bool isTwenty = (age == 20);
    bool isDifferent = (age != 20);

    std::cout << isAdult << '\n';
    std::cout << isTwenty << '\n';
    std::cout << isDifferent << '\n';
    return 0;
}

运行结果如下。

1
1
0

分析:

变量 age 的值为 20,因此 age >= 18 和 age == 20 的计算结果都为 true,而 age != 20 的结果为 false。由于 std::cout 默认把 true 输出为 1、把 false 输出为 0,屏幕上依次打印出 1、1、0。

= 和 == 的区别

初学编程时,最容易写错的就是把双等号(==)误写成单等号(=)。小伙伴们一定要区分清楚两者的作用:

单等号(=)是赋值运算符:表示把右边的值装进左边的变量里,比如 age = 18 表示把 18 赋值给 age。

双等号(==)是比较运算符:表示判断左右两边的值是否相等,比如 age == 18 表示判断 age 的值是不是等于 18。

C++ 逻辑运算符

单个比较运算符只能判断一个条件。如果在实际开发中需要同时满足多个条件,比如判断年龄是否在 18 到 60 岁之间,我们就需要用到逻辑运算符把多个条件组合起来。C++ 中的逻辑运算符共有 3 个,如下表所示。

逻辑运算符
运算符 名称 运算规则 示例
&& 逻辑与 两边都为 true,结果才为 true;否则为 false (a > 0) && (b > 0)
|| 逻辑或 只要有一个为 true,结果就为 true;否则为 false (a > 0) || (b > 0)
! 逻辑非 把 true 变成 false,把 false 变成 true !isAdult

1. 逻辑运算符的基本使用

这 3 个逻辑运算符的规则很直观:&& 要求两边条件同时成立才算真,|| 只要有一边条件成立就算真,而 ! 则是把真假状态反过来。

示例 9:组合多个条件

#include <iostream>

int main() {
    bool hasTicket = true;
    bool isAdult = false;

    bool res1 = hasTicket && isAdult;
    bool res2 = hasTicket || isAdult;
    bool res3 = !isAdult;

    std::cout << res1 << '\n';
    std::cout << res2 << '\n';
    std::cout << res3 << '\n';
    return 0;
}

运行结果如下。

0
1
1

分析:

hasTicket 为 true,isAdult 为 false。计算 hasTicket && isAdult 时有一边为假,因此输出 0。计算 hasTicket || isAdult 时有一边为真,输出 1,而 !isAdult 对 false 取反后同样输出 1。

把比较运算符和逻辑运算符结合使用时要特别小心:如果想判断变量 age 是否在 18 到 60 之间,千万不能像数学不等式那样连着写:

// 正确方式
age >= 18 && age <= 60

// 错误方式
18 <= age <= 60

为什么 18 <= age <= 60 是错的呢?假设 age 是 10,程序从左往右先算左边的 18 <= 10 得到 false,继续比较大小时 false 会当成整数 0 处理。紧接着拿 0 去和右边的 60 比较,即计算 0 <= 60,结果反而变成了 true。因此判断数值区间时,必须拆成两个比较式并用 && 连接起来。

提示 书写逻辑与和逻辑或时,必须连写两个字符 && 和 ||,不要误写成单个的 & 或 |。单个的 & 和 | 用于位运算,含义完全不同。

2. && 和 || 的短路特性

在 C++ 中,逻辑与(&&)和逻辑或(||)还有一个重要特点,叫做 “短路求值”,平时常简称为 “短路”。

所谓短路,指的是 C++ 从左往右计算逻辑表达式时,如果单看左边的条件就已经能确定整个表达式的最终结果,那么右边的表达式就会直接跳过、不再执行:

  • && 的短路:只要左边为 false,整个 && 的结果必定是 false,此时右边直接跳过不执行。
  • || 的短路:只要左边为 true,整个 || 的结果必定是 true,此时右边直接跳过不执行。

示例 10:逻辑与的短路求值

#include <iostream>

int main() {
    int count = 0;
    bool result = false && (++count > 0);

    std::cout << result << '\n';
    std::cout << count << '\n';
    return 0;
}

运行结果如下。

0
0

分析:

从运行结果可以看到,count 输出依然是 0。我们在 && 右边放了一个前置自增 ++count,但由于左边已经是 false,直接触发了短路,右边的 (++count > 0) 根本没有执行。

短路特性在实际开发中非常实用。比如在做除法判断 b != 0 && a / b > 2 时,一旦 b 等于 0,左边 b != 0 为 false 就会立即触发短路,保护右边的 a / b 不会发生除以 0 的崩溃。

上一篇:

下一篇:

给站长反馈

绿叶网正在不断完善中,小伙伴们如果发现任何问题,还望多多给站长反馈,谢谢!

邮箱:lvyenet@vip.qq.com

「绿叶网」服务号
绿叶网服务号放大
关注服务号,微信也能看教程。
绿叶网服务号