运算符
程序最常做的事之一就是算数:一共多少钱、平均几分、还剩多少。C 的加减乘除和数学课上差不多,不过有两个地方常常让人吃惊:7 / 2 等于 3,而 int 也有装不下的时候。
1#include <stdio.h>2 3int main(void) {4 int price = 12;5 int quantity = 3;6 int total = price * quantity;7 printf("合计:%d 元\n", total);8 return 0;9}
合计:36 元
price * quantity 先算出 36,再放进 total。算式可以放在赋值的右边,也可以直接放进 printf。
算术运算符
| 运算符 | 意思 | 例子 | 结果 |
|---|---|---|---|
+ | 加 | 17 + 5 | 22 |
- | 减 | 17 - 5 | 12 |
* | 乘 | 17 * 5 | 85 |
/ | 除 | 17 / 5 | 3 |
% | 取余数 | 17 % 5 | 2 |
1#include <stdio.h>2 3int main(void) {4 int a = 17;5 int b = 5;6 printf("%d + %d = %d\n", a, b, a + b);7 printf("%d - %d = %d\n", a, b, a - b);8 printf("%d * %d = %d\n", a, b, a * b);9 printf("%d / %d = %d\n", a, b, a / b);10 printf("%d %% %d = %d\n", a, b, a % b);11 return 0;12}
17 + 5 = 22 17 - 5 = 12 17 * 5 = 85 17 / 5 = 3 17 % 5 = 2
最后一行的 %% 是第 3 课学的:在 printf 的文字里显示一个 %。
整数除法
两个 int 相除,结果还是 int:小数部分直接丢掉,不四舍五入。所以 17 / 5 是 3,不是 3.4。
1#include <stdio.h>2 3int main(void) {4 printf("%d\n", 7 / 2);5 printf("%d\n", 19 / 4);6 printf("%d\n", 9 / 10);7 return 0;8}
3 4 0
9 / 10 是 0.9,丢掉小数部分就是 0。另外,不能除以 0:这是未定义行为,我们的引擎会停在那一行。
这段程序显示什么?
1#include <stdio.h>2 3int main(void) {4 int minutes = 100;5 printf("%d\n", minutes / 60 * 60);6 return 0;7}
从左往右算:100 / 60 是整数除法,得 1;再 1 * 60,得 60。丢掉的那部分回不来了。
取余数
% 算的是整数除法剩下的余数。一个数除以另一个数,商用 /,余数用 %,两个一起用就很方便:
1#include <stdio.h>2 3int main(void) {4 int eggs = 50;5 int boxes = eggs / 6;6 int left = eggs % 6;7 printf("%d 个鸡蛋:装满 %d 盒,剩 %d 个\n", eggs, boxes, left);8 printf("%d\n", 8 % 2);9 printf("%d\n", 7 % 2);10 return 0;11}
50 个鸡蛋:装满 8 盒,剩 2 个 0 1
一个数 % 2 得 0 就是偶数,不是 0 就是奇数(正数得 1,负的奇数得 -1)。% 只能用在整数上,写 7.5 % 2 会编译错误。
小数除法和类型转换
只要有一边是 double,结果就是 double,小数部分也留着。但是,把整数除法的结果放进 double 已经晚了:
1#include <stdio.h>2 3int main(void) {4 double a = 7.0 / 2;5 double b = 7 / 2.0;6 double c = 7 / 2;7 printf("%f\n", a);8 printf("%f\n", b);9 printf("%f\n", c);10 return 0;11}
3.500000 3.500000 3.000000
c 是 3.000000:7 / 2 两边都是整数,先算出 3,再放进 double。
如果两个数都是 int 变量,比如求平均分,就在前面写 (double),把它转换成 double 再算:
1#include <stdio.h>2 3int main(void) {4 int total = 256;5 int count = 3;6 printf("%.2f\n", (double)total / count);7 printf("%.2f\n", (double)(total / count));8 return 0;9}
85.33 85.00
第一行先把 total 变成 256.0,再除,得 85.33。第二行括号里先做了整数除法,得 85,再转换也找不回小数了。反过来,(int)3.9 得 3,小数部分丢掉。
+= 和 ++
「在原来的值上加一点」太常见了,所以有简写:
| 写法 | 等于 |
|---|---|
balance += 50; | balance = balance + 50; |
balance -= 30; | balance = balance - 30; |
balance *= 2; | balance = balance * 2; |
visits++; | visits = visits + 1; |
visits--; | visits = visits - 1; |
1#include <stdio.h>2 3int main(void) {4 int balance = 100;5 balance += 50;6 balance -= 30;7 balance *= 2;8 printf("余额:%d\n", balance);9 int visits = 0;10 visits++;11 visits++;12 visits--;13 printf("访问:%d 次\n", visits);14 return 0;15}
余额:240 访问:1 次
点单步,看每一行之后 balance 和 visits 变成多少。++ 和 -- 也可以写在前面(++visits),单独一行时效果一样;放进别的算式里时两种写法有区别,先别那样用。
先乘除,后加减
和数学课一样:先算 *、/、%,再算 +、-;同一级的从左往右。想先算哪部分,就加括号。
1#include <stdio.h>2 3int main(void) {4 int a = 80;5 int b = 90;6 int c = 70;7 printf("%d\n", 2 + 3 * 4);8 printf("%d\n", (2 + 3) * 4);9 printf("%d\n", a + b + c / 3);10 printf("%d\n", (a + b + c) / 3);11 return 0;12}
14 20 193 80
第三行想求三科的平均分,可是只有 c 被除以 3,得到 193。加了括号的第四行才是 80。
小技巧: 拿不准谁先算的时候就加括号。多一对括号不花什么,读的人也更省心。
整数溢出
第 2 课说过,int 一般占 4 个字节,能放的数有上限,也有下限。<limits.h> 里的 INT_MAX 和 INT_MIN 就是这两个数:
1#include <stdio.h>2#include <limits.h>3 4int main(void) {5 printf("int 最大:%d\n", INT_MAX);6 printf("int 最小:%d\n", INT_MIN);7 return 0;8}
int 最大:2147483647 int 最小:-2147483648
已经是最大了,再加 1 会怎样?
1#include <stdio.h>2#include <limits.h>3 4int main(void) {5 int views = INT_MAX;6 printf("%d\n", views);7 views = views + 1;8 printf("%d\n", views);9 return 0;10}
2147483647
signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'发生了什么: 停在第 7 行:2147483647 + 1 超出了 int 的范围(结果放不下)。
超出 int 的范围叫溢出,这也是未定义行为。在普通的电脑上,它常常悄悄变成一个很大的负数,程序照样往下跑,错误很难发现。我们的引擎会停在溢出的那一行。数可能很大时(比如全世界的人口),就要换一个更大的类型,比如 long long,以后会见到。
练一练
写好代码,点检查。提示随便看,实在想不出来再看答案。
几小时几分钟
✓把 total_minutes 换算成小时和分钟,显示 2 小时 15 分钟。
2 小时 15 分钟
1#include <stdio.h>2 3int main(void) {4 int total_minutes = 135;5 int hours = 0;6 int minutes = 0;7 printf("%d 小时 %d 分钟\n", hours, minutes);8 return 0;9}
摄氏转华氏
✓华氏温度 = 摄氏温度 × 9 ÷ 5 + 32。算出 fahrenheit,显示 36.6°C = 97.9°F。
36.6°C = 97.9°F
1#include <stdio.h>2 3int main(void) {4 double celsius = 36.6;5 double fahrenheit = 0;6 printf("%.1f°C = %.1f°F\n", celsius, fahrenheit);7 return 0;8}
修好它
✓60 道题答对了 45 道,正确率应该是 75.0%,这段程序却显示 0.0%。改好它,让它显示 正确率:75.0%。
正确率:75.0%
1#include <stdio.h>2 3int main(void) {4 int correct = 45;5 int total = 60;6 double rate = correct / total * 100;7 printf("正确率:%.1f%%\n", rate);8 return 0;9}
这一课学会了
+ - * / %是加、减、乘、除、取余数。- 两个
int相除,小数部分直接丢掉:7 / 2是 3;%给出余数。 - 有一边是
double,结果就是double;两个int变量相除要小数,写(double)a / b。 +=、-=、*=是简写;x++加 1,x--减 1。- 先乘除后加减,同一级从左往右;拿不准就加括号。
int有上限INT_MAX,超出去是溢出,这是未定义行为。