本章目标:搞懂算术、比较、逻辑、位运算、自增自减。 这些都是"小学算术 + 一点点编程逻辑",放心。
int a = 7, b = 2;
a + b // 9
a - b // 5
a * b // 14
a / b // 3 ← 整数除以整数,结果是整数!小数被丢掉
a % b // 1 ← 取余数(模运算)
坑 1:整数除法
7 / 2 == 3(不是 3.5)。想要小数,先把一个转成 double:
double r = 7.0 / 2; // 3.5
坑 2:除以 0
整数除以 0 是"未定义行为"——程序可能崩溃、可能出错值,
编译器不保证任何事。**永远不要除以 0**。
坑 3:负数的 % 结果符号
-7 % 2 == -1(跟随被除数的符号)。知道即可。
a += 5; // 等价于 a = a + 5
a -= 5; // a = a - 5
a *= 2;
a /= 2;
a %= 3;
很常用,读作"a 加等于 5"。
int i = 0;
i++; // i 变成 1(i = i + 1 的缩写)
i--; // i 变回 0
前后位置的区别:
int j = i++; // j = i 原来的值,然后 i 加 1(先取值再加)
int k = ++i; // i 先加 1,然后 k = i(先加再取值)
人话:i++ 是"用完了再加",++i 是"加完了再用"。 单独写一行时它俩没区别。循环里大量使用。
a == b // 相等(注意是 ==,两个等号!)
a != b // 不相等
a < b // 小于
a > b // 大于
a <= b // 小于等于
a >= b // 大于等于
新手第一大错误:把 == 写成 =。
if (a = 5) // 这不是比较!是把 5 赋给 a,然后 a 恒为真
if (a == 5) // 这才是比较
!a // 非(取反):true 变 false
a && b // 与(且):两个都真才真
a || b // 或:有一个真就真
短路特性(重要):
if (ptr != nullptr && *ptr > 0)
// 如果 ptr 是空指针,&& 左边为假,右边根本不会执行!
// 这就是"短路":能提前判断就不往后算。
这让我们能安全地写"先检查再使用"的代码。
按二进制位操作:
a & b // 按位与
a | b // 按位或
a ^ b // 按位异或(不同为 1)
~a // 按位取反
a << 2 // 左移 2 位 = 乘 4(快)
a >> 2 // 右移 2 位 = 除以 4(向下取整)
经典用途:
int flags = 0;
flags |= (1 << 0); // 打开第 0 位
bool on = flags & (1 << 0); // 检查第 0 位
新手不用背位运算,知道"有这个工具"即可,用到再查。
int max = (a > b) ? a : b;
// 读作:a > b 吗?真就取 a,假就取 b
等价于:
int max;
if (a > b) max = a; else max = b;
短、清晰时用三目;复杂条件用 if。
优先级从高到低(常见部分):
1. () 括号
2. ! ~ ++ --
3. * / %
4. + -
5. << >>
6. < <= > >=
7. == !=
8. &
9. ^
10. |
11. &&
12. ||
13. = 赋值
经验:**表达式中混用不同类运算符时,用括号明确意图**。 别人读你代码时不用翻表,你自己也不用。
if ((a & b) == 0) // 括号保证先算位运算再比较
int x = static_cast<int>(3.99); // 3,丢小数
double d = static_cast<double>(3); // 3.0
一句话:显式写出来,读者和你自己都清楚"这里故意转类型"。
练习题