C: 运算符与表达式
运算符就像厨房里的工具——切菜用刀,炒菜用锅,不同的食材需要不同的工具,不同的计算也需要不同的运算符。
1. 算术运算符
C语言提供了7个基本算术运算符,用来完成最常见的数学计算。
| 运算符 | 含义 | 示例 | 结果 |
|---|---|---|---|
+ |
加法 | 5 + 3 |
8 |
- |
减法 | 5 - 3 |
2 |
* |
乘法 | 5 * 3 |
15 |
/ |
除法 | 7 / 2 |
3 |
% |
取余 | 7 % 2 |
1 |
+ |
正号 | +5 |
5 |
- |
负号 | -5 |
-5 |
(1) 整数除法的陷阱
两个整数相除,结果还是整数,小数部分直接丢弃,不是四舍五入。
C
#include <stdio.h>
int main(void) {
int a = 7;
int b = 2;
printf("%d / %d = %d\n", a, b, a / b);
printf("%d %% %d = %d\n", a, b, a % b);
return 0;
}
TEXT
📖 仅展示
7 / 2 = 3
7 % 2 = 1
💡 想得到带小数的结果,至少让一个操作数是浮点数:
7.0 / 2 结果是 3.5。
(2) 取余运算的用途
取余运算 % 只能用于整数,它有几个非常实用的场景:
- 判断奇偶:
n % 2为0则是偶数 - 取末位数字:
n % 10得到个位数 - 循环索引:
i % size让索引在0到size-1之间循环
C
#include <stdio.h>
int main(void) {
int n = 12345;
printf("个位数: %d\n", n % 10);
printf("是否偶数: %s\n", n % 2 == 0 ? "是" : "否");
return 0;
}
TEXT
📖 仅展示
个位数: 5
是否偶数: 否
2. 自增与自减运算符
自增 ++ 让变量加1,自减 -- 让变量减1。它们各有两种写法:前置和后置,区别在于表达式的返回值不同。
(1) 前置与后置的区别
| 写法 | 名称 | 效果 | 表达式的值 |
|---|---|---|---|
++i |
前置自增 | i先加1 | 加1后的新值 |
i++ |
后置自增 | i先加1 | 加1前的旧值 |
--i |
前置自减 | i先减1 | 减1后的新值 |
i-- |
后置自减 | i先减1 | 减1前的旧值 |
C
#include <stdio.h>
int main(void) {
int a = 5;
int b = ++a;
printf("前置: a=%d, b=%d\n", a, b);
int c = 5;
int d = c++;
printf("后置: c=%d, d=%d\n", c, d);
return 0;
}
TEXT
📖 仅展示
前置: a=6, b=6
后置: c=6, d=5
⚠️ 不要在同一个表达式中对同一个变量多次使用自增自减,如
a = ++a + a++,行为未定义,不同编译器结果不同。
3. 关系运算符
关系运算符用来比较两个值,结果是"真"(1) 或"假"(0)。
| 运算符 | 含义 | 示例 | 结果 |
|---|---|---|---|
== |
等于 | 5 == 5 |
1 |
!= |
不等于 | 5 != 3 |
1 |
< |
小于 | 3 < 5 |
1 |
> |
大于 | 3 > 5 |
0 |
<= |
小于等于 | 5 <= 5 |
1 |
>= |
大于等于 | 3 >= 5 |
0 |
C
#include <stdio.h>
int main(void) {
int a = 10;
int b = 20;
printf("a == b: %d\n", a == b);
printf("a != b: %d\n", a != b);
printf("a < b: %d\n", a < b);
return 0;
}
TEXT
📖 仅展示
a == b: 0
a != b: 1
a < b: 1
⚠️
== 是比较,= 是赋值,写错会变成赋值且不会报错。建议把常量写在左边:5 == a,如果误写成 5 = a 编译器会报错。
4. 逻辑运算符
逻辑运算符用于组合多个条件,结果同样是1(真)或0(假)。
| 运算符 | 含义 | 示例 | 结果 |
|---|---|---|---|
&& |
逻辑与 | 1 && 0 |
0 |
|| |
逻辑或 | 1 || 0 |
1 |
! |
逻辑非 | !0 |
1 |
(1) 真值表
| A | B | A && B | A || B | !A |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 1 |
| 0 | 1 | 0 | 1 | 1 |
| 1 | 0 | 0 | 1 | 0 |
| 1 | 1 | 1 | 1 | 0 |
(2) 短路求值
&& 如果左边为假,右边不再计算;|| 如果左边为真,右边不再计算。这个特性可以用来避免非法操作:
C
#include <stdio.h>
int main(void) {
int divisor = 0;
int value = 10;
if (divisor != 0 && value / divisor > 5) {
printf("条件成立\n");
} else {
printf("条件不成立,且没有除以零\n");
}
return 0;
}
TEXT
📖 仅展示
条件不成立,且没有除以零
💡 C语言中,0为假,任何非0值都为真(包括负数)。所以
-5 在逻辑判断中也是"真"。
5. 赋值运算符
基本赋值运算符 = 把右边的值存入左边的变量。C还提供了复合赋值运算符,把运算和赋值合二为一。
| 复合赋值 | 等价写法 |
|---|---|
a += b |
a = a + b |
a -= b |
a = a - b |
a *= b |
a = a * b |
a /= b |
a = a / b |
a %= b |
a = a % b |
C
#include <stdio.h>
int main(void) {
int score = 80;
score += 10;
printf("加分后: %d\n", score);
score -= 25;
printf("扣分后: %d\n", score);
score *= 2;
printf("翻倍后: %d\n", score);
return 0;
}
TEXT
📖 仅展示
加分后: 90
扣分后: 65
翻倍后: 130
6. 条件运算符(三目运算符)
条件运算符 ?: 是C语言中唯一的三目运算符,语法为:
C
条件 ? 表达式1 : 表达式2
条件为真执行表达式1,否则执行表达式2。它是 if-else 的简写形式。
C
#include <stdio.h>
int main(void) {
int age = 20;
char *status = age >= 18 ? "成年" : "未成年";
printf("年龄%d,%s\n", age, status);
int a = 15, b = 28;
int max = a > b ? a : b;
printf("较大值: %d\n", max);
return 0;
}
TEXT
📖 仅展示
年龄20,成年
较大值: 28
7. 逗号运算符
逗号运算符 , 从左到右依次执行每个表达式,整个逗号表达式的值是最后一个表达式的值。
C
#include <stdio.h>
int main(void) {
int a, b, c;
c = (a = 1, b = 2, a + b);
printf("a=%d, b=%d, c=%d\n", a, b, c);
return 0;
}
TEXT
📖 仅展示
a=1, b=2, c=3
⚠️ 逗号运算符的优先级是所有运算符中最低的。注意区分"逗号运算符"和函数参数之间的逗号——后者不是逗号运算符。
8. sizeof 运算符
sizeof 用来获取数据类型或变量占用的内存字节数。它在编译时求值,不是运行时。
C
#include <stdio.h>
int main(void) {
printf("char: %zu 字节\n", sizeof(char));
printf("int: %zu 字节\n", sizeof(int));
printf("float: %zu 字节\n", sizeof(float));
printf("double: %zu 字节\n", sizeof(double));
int arr[5] = {1, 2, 3, 4, 5};
printf("数组总大小: %zu 字节\n", sizeof(arr));
printf("数组元素数: %zu\n", sizeof(arr) / sizeof(arr[0]));
return 0;
}
TEXT
📖 仅展示
char: 1 字节
int: 4 字节
float: 4 字节
double: 8 字节
数组总大小: 20 字节
数组元素数: 5
💡
sizeof 对类型名要用括号(sizeof(int)),对变量可以不用括号(sizeof a),但为了统一风格,建议都加括号。
9. 运算符优先级
当一个表达式中有多个运算符时,优先级高的先计算。下表从高到低排列:
| 优先级 | 运算符 | 结合方向 |
|---|---|---|
| 1(最高) | () [] -> . |
左到右 |
| 2 | ! ~ ++ -- +(正) -(负) *(解引用) &(取址) sizeof |
右到左 |
| 3 | * / % |
左到右 |
| 4 | + - |
左到右 |
| 5 | << >> |
左到右 |
| 6 | < <= > >= |
左到右 |
| 7 | == != |
左到右 |
| 8 | & |
左到右 |
| 9 | ^ |
左到右 |
| 10 | | |
左到右 |
| 11 | && |
左到右 |
| 12 | || |
左到右 |
| 13 | ?: |
右到左 |
| 14 | = += -= *= /= %= 等 |
右到左 |
| 15(最低) | , |
左到右 |
🔥 记不住优先级?不用死记——不确定时就加括号,括号永远最优先,而且让代码更清晰。
▶ 示例
综合运用各类运算符,计算一个三位数的各位数字之和:
C
#include <stdio.h>
int main(void) {
int num = 952;
int hundreds = num / 100;
int tens = (num / 10) % 10;
int ones = num % 10;
int sum = hundreds + tens + ones;
printf("数字: %d\n", num);
printf("百位: %d, 十位: %d, 个位: %d\n", hundreds, tens, ones);
printf("各位数字之和: %d\n", sum);
return 0;
}
TEXT
📖 仅展示
数字: 952
百位: 9, 十位: 5, 个位: 2
各位数字之和: 16
▶ 示例
利用逻辑运算符和关系运算符,判断某年是否为闰年:
C
#include <stdio.h>
int main(void) {
int year = 2024;
int is_leap = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
printf("%d年%s闰年\n", year, is_leap ? "是" : "不是");
return 0;
}
TEXT
📖 仅展示
2024年是闰年
10. 类型转换
(1) 隐式转换
当不同类型的数据参与运算时,编译器会自动将低精度类型转换为高精度类型:
C
#include <stdio.h>
int main(void) {
int a = 5;
double b = 2.0;
double c = a / b;
printf("5 / 2.0 = %f\n", c);
char ch = 'A';
int code = ch + 1;
printf("'A' + 1 = %c (ASCII %d)\n", code, code);
return 0;
}
TEXT
📖 仅展示
5 / 2.0 = 2.500000
'A' + 1 = B (ASCII 66)
转换方向:char → int → long → double,int → unsigned → long → double。
(2) 强制转换
用 (类型名) 可以强制将一个值转为指定类型:
C
#include <stdio.h>
int main(void) {
int a = 7, b = 2;
double result = (double)a / b;
printf("强制转换: %f\n", result);
return 0;
}
TEXT
📖 仅展示
强制转换: 3.500000
⚠️ 强制转换不改变原变量的值和类型,它只是产生一个临时的新值。
❓ 常见问题
Q
a++ 和 ++a 在单独一行时有区别吗?A 没有区别。只有在表达式中使用返回值时才不同,单独使用效果完全一样,但前置自增理论上级稍高。
Q
= 和 == 到底怎么区分?A
= 是赋值("变成"),== 是比较("等于吗")。在if条件中误写成 if (a = 0) 不会报错但逻辑全错,建议常量写左边 if (0 == a)。Q 取余运算
% 能用于浮点数吗?A 不能。
% 只能用于整数类型。浮点数取余要用 fmod() 函数,需要 #include <math.h>。Q 运算符优先级需要全部背诵吗?
A 不需要。记住乘除模优先于加减、逻辑非优先于与优先于或就够了,其余情况加括号更安全。
📖 小节
- 算术运算符中,整数除法截断小数、取余只能用于整数
++/--前置返回新值,后置返回旧值;避免在同一表达式中对同一变量多次使用- 关系运算符结果是0或1,谨防
=与==混淆 - 逻辑运算符
&&和||有短路求值特性,可以保护右侧表达式 - 运算符优先级不必死记,拿不准就加括号
📝 作业
- 编写程序,输入一个秒数(如3661),用
/和%计算出对应的小时、分钟和秒并输出。 - 编写程序,输入两个整数,用三目运算符找出较大值和较小值并输出。
- 编写程序,用
sizeof输出你电脑上short、int、long、long long的大小,观察结果。