📄 一句话概括
= 不是"等于",是"从右往左装盒子"。复合赋值 += -= *= /= %= 是"先算术、再装回原盒子"的偷懒简写——循环计数里天天见。
一、= 的规矩:从右往左
2.3.2 讲过:= 的执行顺序是先算右边,再把结果装进左边的盒子。
两个推论:
- 左边必须是个"盒子"(能装东西的地方)。
2 = a编译报错——常数 2 没有盒子。这正好呼应 3.1.2 的"常量放左边"防手滑神技:5 = score必报错。 - 连等号从右往左依次装:
a = b = c = 0;等价于先c = 0,再b = c,最后a = b。三个盒子同时清零,一行搞定。
为什么连等号能成立? 因为赋值表达式本身有值——c = 0 这个式子算完的"值"就是 0(顺便把 0 装进了 c)。这个值再被 = 装进 b,以此类推。3.3.1 讲表达式时你会再见到"赋值也有值"这件事。
二、复合赋值家族:先算术,再装回原盒
| 写法 | 等价于 | 含义 |
|---|---|---|
a += 3 |
a = a + 3 |
在 a 原来的值上加 3,装回 a |
a -= 3 |
a = a - 3 |
减 3 装回 |
a *= 3 |
a = a * 3 |
乘 3 装回 |
a /= 3 |
a = a / 3 |
除 3 装回(整数除法丢小数) |
a %= 3 |
a = a % 3 |
取余装回 |
五个复合符号的后半截,正好对应 3.1.1 的算术五兄弟——一个不少。
两个细节:
a *= b + 2等价于a = a * (b + 2)——右边整体先算完再运算,相当于自带一对括号a /= 3对int是整除(3.1.1 坑一),对double是正常除法——复合赋值不改变除法的规矩
三、为什么会有这套简写?
不是卖弄语法,是真用得频繁:
count += 1; // 计数器 +1(循环里每转一圈数一个)
sum += score; // 累加器:把新分数加进总和
product *= n; // 累乘器:阶乘、连乘
"把某变量的新值,基于旧值算出来再存回去"——这个动作在程序里到处都是,所以每个语言都给它配了简写。第 5 章 for 循环里,i += 1(或 i++)几乎是每段循环的标配零件。
四、动手 Demo:累加器 + 累乘器
#include <iostream>
using namespace std;
int main() {
int a = 10;
a += 5; cout << a << endl; // 15
a -= 3; cout << a << endl; // 12
a *= 2; cout << a << endl; // 24
a /= 5; cout << a << endl; // 4(24/5=4.8 丢小数!)
a %= 3; cout << a << endl; // 1
// 连等号:三个盒子同时清零
int x = 1, y = 2, z = 3;
x = y = z = 0;
cout << x << y << z << endl; // 000
return 0;
}
看到什么算成功:输出 15 12 24 4 1 和 000。重点盯 24 / 5 = 4——复合赋值里的整数除法照样丢小数,坑不因为你换了写法就绕开。
30 秒实验:把 a /= 5 改成 a = a / 5.0;——注意 a 是 int,结果还是 4(先算出 4.8,装进 int 盒子时再砍一次)。类型转换的完整规矩在 3.3.2 细讲。
五、常见误区
- "
a += 3只是少打几个字,没区别"——多数情况等价,但右边是复杂式子时,a[f(x)] += 1保证"取盒子"这个动作只做一次。现阶段记住简写常用、可读性好即可。 - "
a *= b + 2是先乘 b 再加 2"——反了,右边整体先算:a = a * (b + 2)。 - "连等号是从左往右"——从右往左。
a = b = c = 0先装 c。 - "
=和==混着用没事"——3.1.2 头号坑,本节再敲一次黑板:=改盒子、==问相等。
自测四问(点开对答案)
1. `a = 7; a %= 4;` 之后 a 是多少?——`3`(7 除 4 余 3)。 2. `x = y = z = 0;` 的执行顺序?——先 `z = 0`,再 `y = z`,最后 `x = y`(从右往左)。 3. `a = 5; a *= 2 + 1;` 之后 a 是多少?——`15`(右边整体先算:5×3)。 4. `2 = a;` 会怎样?——编译报错,常数 2 不是可赋值的盒子(呼应 3.4 的"左值"概念)。- ☐ 3.1.5 位运算符(下一节,含实例02)