Kodewick
第 4 课,共 30 课目录

运算符

第 4 课,共 30 课 · 第 1 部分 · 起步 · 约 15 分钟

程序里大多数事情都离不开计算:总价、平均分、还剩多少。C++ 的加减乘除写法和数学里差不多,乘号是 *,除号是 /:

main.cpp
1#include <iostream>2 3int main() {4    int apples = 12;5    int pears = 5;6    std::cout << apples + pears << '\n';7    std::cout << apples - pears << '\n';8    std::cout << apples * pears << '\n';9    std::cout << apples / pears << '\n';10    return 0;11}
输出
17
7
60
2

前三行没什么意外。最后一行,12 除以 5 不是 2.4,而是 2。

整数除法和余数

两个 int 相除,结果还是 int:小数部分直接丢掉,不四舍五入。想要被丢掉的那部分,用 % 取余数:

main.cpp
1#include <iostream>2 3int main() {4    int minutes = 135;5    std::cout << minutes / 60 << " 小时\n";6    std::cout << minutes % 60 << " 分钟\n";7    return 0;8}
输出
2 小时
15 分钟

135 分钟里有 2 个完整的 60,剩下 15。% 很常用:n % 2 是 0 就是偶数,n % 10 是最后一位数字。% 只能用在整数上。

先猜一猜

8 块披萨分给 3 个人,这段程序显示什么?

1#include <iostream>2 3int main() {4    int slices = 8;5    int people = 3;6    std::cout << slices / people << " " << slices % people << '\n';7    return 0;8}

static_cast:要小数的结果

求平均数时,整数除法就是个坑:

main.cpp
1#include <iostream>2 3int main() {4    int total = 7;5    int count = 2;6    double wrong = total / count;7    double right = static_cast<double>(total) / count;8    std::cout << wrong << '\n';9    std::cout << right << '\n';10    return 0;11}
输出
3
3.5

wrong 虽然是 double,但 total / count 在放进去之前已经算成了整数 3。static_cast<double>(total) 先把 total 变成 double 7.0,再除,就是小数除法,得到 3.5。只要两边有一个是 double,除法就带小数:写 7.0 / 2 也一样。

小技巧: 你在 C 代码里会看到 (double)total 这种写法,效果一样。C++ 里用 static_cast,它更显眼,也更好搜索。

+= 和 ++

「在原来的基础上加多少」太常见了,所以有简写:stock += 5 就是 stock = stock + 5。-=、*=、/=、%= 也一样。加 1 和减 1 还能更短:++count 和 --count。

main.cpp
1#include <iostream>2 3int main() {4    int stock = 10;5    stock += 5;6    stock -= 3;7    stock *= 2;8    int sold = 0;9    ++sold;10    ++sold;11    std::cout << "库存:" << stock << ",卖出:" << sold << '\n';12    return 0;13}
输出
库存:24,卖出:2

点单步,看 stock 从 10 变成 15、12、24。++ 写在前面(++sold)或后面(sold++)都行,单独一行时效果一样。这门课把它单独写成一行,不放进更长的式子里。

先乘除,后加减

和数学一样,先算 *、/、%,后算 +、-;同一级的从左往右算。拿不准的时候就加括号:

main.cpp
1#include <iostream>2 3int main() {4    int a = 80;5    int b = 90;6    std::cout << a + b / 2 << '\n';7    std::cout << (a + b) / 2 << '\n';8    std::cout << 10 - 4 - 3 << '\n';9    return 0;10}
输出
125
85
3

第一行先算 b / 2 是 45,再加 80,得到 125,不是平均分。加上括号才是 85。10 - 4 - 3 从左往右算,是 3。

先猜一猜

这段程序显示什么?

1#include <iostream>2 3int main() {4    std::cout << 2 + 3 * 4 << '\n';5    return 0;6}

int 的上限

int 通常占 4 个字节,能放的数有最大也有最小。<climits> 里的 INT_MAX 和 INT_MIN 就是最大和最小的那两个数。<limits> 里的 std::numeric_limits<int>::max() 和 min() 是另一种写法,换成别的类型也能用:

main.cpp
1#include <iostream>2#include <climits>3#include <limits>4 5int main() {6    std::cout << INT_MAX << '\n';7    std::cout << INT_MIN << '\n';8    std::cout << std::numeric_limits<int>::max() << '\n';9    std::cout << std::numeric_limits<long long>::max() << '\n';10    return 0;11}
输出
2147483647
-2147483648
2147483647
9223372036854775807

int 大约正负 21 亿,第三行和第一行是同一个数;最后一行是 long long 的最大值,大得多。超出这个范围叫溢出。看看最大的数再加 1 会怎样:

main.cpp
1#include <iostream>2#include <climits>3 4int main() {5    int views = INT_MAX;6    std::cout << "现在:" << views << '\n';7    views = views + 1;8    std::cout << "加 1:" << views << '\n';9    return 0;10}
输出
现在:2147483647
signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'

发生了什么: 停在第 7 行:2147483647 + 1 超出了 int 的范围(结果放不下)。

int 溢出是未定义行为。在普通的电脑上,它常常悄悄变成一个很大的负数,程序接着跑,错误很难发现。我们的引擎会停在溢出的那一行。数可能很大时(比如世界人口、以分为单位的金额),换成 long long,它能放到大约 9×10¹⁸。

sqrt 和 pow

开平方、乘方这些数学函数在 <cmath> 里。std::sqrt(x) 是平方根,std::pow(x, y) 是 x 的 y 次方,结果都是 double:

main.cpp
1#include <iostream>2#include <cmath>3 4int main() {5    std::cout << std::sqrt(16.0) << '\n';6    std::cout << std::pow(2, 10) << '\n';7    double a = 3;8    double b = 4;9    std::cout << "斜边:" << std::sqrt(a * a + b * b) << '\n';10    return 0;11}
输出
4
1024
斜边:5

C++ 没有乘方运算符:2 ^ 10 能编译,但 ^ 是另一种运算,结果是 8,不是 1024。乘方就用 std::pow,平方直接写 a * a。

练一练

写好代码,点检查。提示随便看,实在想不出来再看答案。

练习 1

三门课的平均分

现在程序显示的是 平均分:89。改一改,让它显示带小数的平均分 平均分:89.6667。

要显示
平均分:89.6667
exercise1.cpp
1#include <iostream>2 3int main() {4    int math = 85;5    int english = 90;6    int science = 94;7    int total = math + english + science;8    std::cout << "平均分:" << total / 3 << '\n';9    return 0;10}
输出
点「运行」或按 Ctrl+Enter
练习 2

分钟换成小时

用 / 和 %,把 minutes 换成小时和分钟,显示 200 分钟是 3 小时 20 分钟。

要显示
200 分钟是 3 小时 20 分钟
exercise2.cpp
1#include <iostream>2 3int main() {4    int minutes = 200;5 6    return 0;7}
输出
点「运行」或按 Ctrl+Enter
练习 3

修好它:放不下的步数

运行一下:引擎停在了溢出的那一行。改好它,让它显示 4000000000。

要显示
4000000000
exercise3.cpp
1#include <iostream>2 3int main() {4    int steps = 2000000000;5    int total = steps + steps;6    std::cout << total << '\n';7    return 0;8}
输出
点「运行」或按 Ctrl+Enter

这一课学会了

  • + - * / 是加减乘除;两个 int 相除是整数除法,小数部分丢掉。
  • % 是余数,只用于整数:n % 2 看奇偶,n % 10 取最后一位。
  • static_cast<double>(x) 把 x 变成 double,除法就带小数了。
  • x += 5 是 x = x + 5 的简写;++x 加 1,--x 减 1。
  • 先乘除后加减,同级从左往右;拿不准就加括号。
  • int 最大是 INT_MAX(std::numeric_limits<int>::max()),大约 21 亿;溢出是未定义行为,大数用 long long。
  • <cmath> 里有 std::sqrt 和 std::pow;^ 不是乘方。