Skip to content

第 3 章 运算符与表达式 ​

本章目标

把“算数”这件事彻底搞明白: 加减乘除怎么算、为什么 / 会得到小数、idiv 和 % 怎么用、 比较与逻辑怎么写、位运算是什么、优先级怎么记。学完你能算价格、拆时间、做判断、写公式。

3.1 算术运算符 ​

运算符含义例子结果
+加 (或字符串拼接)2 + 35
-减10 - 46
*乘6 * 742
/浮点除法7 / 23.5
%取余 (只支持整数)7 % 21
-x取负-5-5

3.2 最大的坑: / 永远是浮点除法 ​

这是初学者最容易写错的地方。CIN 里 / 不做整数除法:

cin
function main() -> int {
    println("7 / 2 = " + (7 / 2))              // 3.5, 不是 3
    println("idiv(7, 2) = " + idiv(7, 2))      // 3   整数商
    println("7 % 2 = " + (7 % 2))              // 1   余数
    println("idiv(-7, 2) = " + idiv(-7, 2))    // -3  向零截断
    println("-7 % 2 = " + (-7 % 2))            // -1  余数符号跟被除数
    println("idiv(7, -2) = " + idiv(7, -2))    // -3
    return 0
}
text
7 / 2 = 3.5
idiv(7, 2) = 3
7 % 2 = 1
idiv(-7, 2) = -3
-7 % 2 = -1
idiv(7, -2) = -3

记忆口诀: 要小数用 /, 要整数商用 idiv(a, b), 要余数用 %。

把 / 的结果存进 int 会被截断

cin
int q = 7 / 2        // 3.5 赋给 int -> 3 (截断)
int q2 = idiv(7, 2)  // 3 (推荐写法, 意图明确)

两者结果一样, 但 idiv 让你的意图一目了然, 也避免以后改动时踩坑。

3.3 浮点运算与取整 ​

cin
function main() -> int {
    float a = 10.0 / 4.0
    float b = 10 / 4                 // 整数参与也按浮点算
    println("a = " + a)
    println("b = " + b)

    float price = 19.9
    int yuan = price                 // 截断取整: 19
    println("yuan = " + yuan)
    return 0
}
text
a = 2.5
b = 2.5
yuan = 19

想要“四舍五入到两位小数”这种效果, 用整数“分”来算最稳:

cin
function main() -> int {
    float price = 12.5
    int qty = 7
    float total = price * qty            // 87.5
    int cents = round(total * 100)       // 8750 (分)
    println("总价 = " + idiv(cents, 100) + "." + (cents % 100))
    return 0
}
text
总价 = 87.50

注意: cents % 100 是 50 时显示 .50, 但如果是 5 会显示 .5。 想要固定两位需要补零 (见 转换库 c_pad_int)。

3.4 比较运算符 ​

运算符含义例子结果
==等于3 == 3true
!=不等于3 != 4true
> <大于 / 小于5 > 2true
>= <=大于等于 / 小于等于5 <= 5true

字符串不能用 == 比内容

== 比较的是字符串的地址。两个内容相同的字符串可能是 false:

cin
string a = "ab" + "c"      // 运行时拼出来的新字符串
string b = "abc"           // 源码里的字面量
println(a == b)            // false (地址不同!)
println(strcmp(a, b) == 0) // true  (按内容比较, 正确做法)
text
false
true

规则: 字符串一律用 strcmp(a, b) == 0 判断相等, strcmp(a, b) < 0 判断“字典序在前”。

3.5 逻辑运算符与短路求值 ​

运算符含义说明
&&与两边都真才为真
||或只要一边为真就为真
!非真变假、假变真

短路: && 左边为假时右边不执行; || 左边为真时右边不执行。用带打印的函数能直接看到:

cin
function side(int tag) -> bool {
    println("  (求值 " + tag + ")")
    return true
}

function main() -> int {
    bool a = false && side(1)      // 左边为假, 右边不求值
    bool b = true || side(2)       // 左边为真, 右边不求值
    bool c = true && side(3)       // 必须求值右边
    println("a=" + a + " b=" + b + " c=" + c)
    return 0
}
text
  (求值 3)
a=false b=true c=true

短路是安全网

if (i < n && arr[i] > 0) —— 当 i >= n 时右边不会被求值, 因此不会去读越界的 arr[i]。 把“范围检查”写在左边是常用技巧。

3.6 位运算 (进阶, 可以先跳过) ​

位运算直接操作整数的二进制位, 在掩码、标志位、性能优化里常用:

运算符名称例子结果
&按位与0b1100 & 0b10108
|按位或0b1100 | 0b101014
^按位异或0b1100 ^ 0b10106
~按位取反~0-1
<<左移1 << 416
>>算术右移-16 >> 2-4
cin
function main() -> int {
    int a = 0b1100 & 0b1010
    int b = 0b1100 | 0b1010
    int c = 0b1100 ^ 0b1010
    println("and=" + a + " or=" + b + " xor=" + c)

    int d = 1 << 4
    int e = -16 >> 2
    int f = ~0
    println("shl=" + d + " asr=" + e + " not=" + f)
    return 0
}
text
and=8 or=14 xor=6
shl=16 asr=-4 not=-1
  • 0b1100 是二进制字面量 (等于十进制的 12); 也可以用 0x 十六进制、0o 八进制;
  • << 左移一位相当于乘 2, >> 右移一位相当于除以 2 (负数保留符号);
  • 位运算只能用于整数, 对 float 使用会报错。

3.7 复合赋值与自增自减 ​

cin
function main() -> int {
    int x = 10
    x += 5          // 15
    x -= 3          // 12
    x *= 2          // 24
    x /= 4          // 6  (浮点除法结果 6.0, 存入 int 截断)
    println("x = " + x)

    int y = 5
    int pre = ++y   // 先加 1, 表达式值是新值 6
    int post = y--  // 表达式值是旧值 6, 然后 y 变成 5
    println("pre=" + pre + " post=" + post + " y=" + y)
    return 0
}
text
x = 6
pre=6 post=6 y=5

别在一行里做太多自增

x++ 和 ++x 单独成句时没有区别; 混在复杂表达式里会让代码难读, 建议一次只改一个变量。

3.8 三目运算符: 一行写完 if-else ​

语法: 条件 ? 条件为真时的值 : 条件为假时的值

cin
function main() -> int {
    int score = 72
    println(score >= 60 ? "及格" : "不及格")

    int x = -3
    int abs_x = x < 0 ? -x : x
    println("abs_x = " + abs_x)
    return 0
}
text
及格
abs_x = 3

3.9 优先级: 不确定就加括号 ​

从高到低 (简化版):

优先级运算符
最高() 括号、f() 调用、[] 下标、x++ x--
↑! ~ -x ++x --x
* / %
+ - (含字符串拼接)
<< >>
< > <= >=
== !=
&
^
|
&&
||
最低?: 与各类赋值 = += …
cin
function main() -> int {
    println("2 + 3 * 4 = " + (2 + 3 * 4))          // 14
    println("(2 + 3) * 4 = " + ((2 + 3) * 4))      // 20
    println("10 - 4 - 3 = " + (10 - 4 - 3))        // 3  (同级从左到右)
    println("2 + 3 == 5 -> " + (2 + 3 == 5))       // true
    return 0
}
text
2 + 3 * 4 = 14
(2 + 3) * 4 = 20
10 - 4 - 3 = 3
2 + 3 == 5 -> true

完整优先级表见 运算符参考。

3.10 常用数学函数 ​

内建函数 (不需要 import) 可以直接用:

cin
function main() -> int {
    println("sqrt(16) = " + sqrt(16))        // 4
    println("pow(2, 10) = " + pow(2, 10))    // 1024
    println("abs(-7) = " + abs(-7))          // 7
    println("floor(3.7) = " + floor(3.7))    // 3 (向下取整)
    println("ceil(3.2) = " + ceil(3.2))      // 4 (向上取整)
    println("round(2.5) = " + round(2.5))    // 3 (四舍五入)
    println("min(3, 9) = " + min(3, 9))      // 3
    println("max(3, 9) = " + max(3, 9))      // 9
    return 0
}
text
sqrt(16) = 4
pow(2, 10) = 1024
abs(-7) = 7
floor(3.7) = 3
ceil(3.2) = 4
round(2.5) = 3
min(3, 9) = 3
max(3, 9) = 9

数学函数取值域要自己检查

sqrt(-1) 这类非法输入在不同执行路径下表现不同 (实测): Go 原生路径打印 NaN, 纯 Python 路径直接报 Execution Error: expected a nonnegative input 并退出码 1。 调用前先自己判断, 例如 if (x >= 0) { ... sqrt(x) ... }, 这样两条路径行为一致。

3.11 常见错误 ​

现象原因解决
想要整数却得到 3.5/ 是浮点除法用 idiv(a, b)
Float modulo not supported对 float 用了 %先转成整数再取余
Bitwise operator ... requires integer operands对 float/string 用了位运算位运算只用于整数
字符串比较结果不对用了 ==用 strcmp(a, b) == 0
拼接顺序不对+ 是从左到右用括号包住先算的部分
循环里越界崩溃&& 两侧顺序写反把范围检查放左边 (短路)

3.12 练习 ​

  1. 计算并打印 17 / 5、idiv(17, 5)、17 % 5 三个结果, 解释差别。
  2. 把 89 分钟换算成“1 小时 29 分”的形式。
  3. 用三目运算符打印 n = 7 是不是偶数。
  4. 给定 int flags = 0b1010, 判断第 3 位 (从 0 开始数) 是 0 还是 1 (提示: & (1 << 3))。
  5. 让用户体重 (kg) 与身高 (m) 固定为 68.5 和 1.75, 计算 BMI 并保留两位小数。

参考实现见 习题与答案 · 第 3 章。

3.13 本章小结 ​

  • / 是浮点除法, 整数商用 idiv, 余数用 %; 负数的 % 结果符号跟被除数;
  • 浮点别用 ==, 用差值判断; 想要两位小数用“分”做整数运算;
  • 字符串比较用 strcmp, 不要用 ==;
  • && / || 会短路, 把安全检查写在左边;
  • 位运算只用于整数; 优先级不确定就加括号;
  • 数学函数返回值域非法时各路径表现可能不同, 自己先判断。

下一章: 条件分支。

文档由 VitePress 构建