变量把数据存起来,输入输出让数据流起来。但程序真正干活的部分,是把存进来的数据拿去做运算——加减乘除、比较大小、判断真假、甚至摆弄二进制位。这些动作,全都靠运算符来完成。
运算符就是 C 语言里的“操盘手”:它们决定数据怎么变,关系怎么判,逻辑怎么走。今天这篇文章,我们就一次把 C 语言常用的运算符认全。不用担心记不住,你可以把它当作“速查手册”,用到的时候回来看一看就行。
一、算术运算符:最基本的加减乘除
C 语言提供了五种基本算术运算符:
| 运算符 | 含义 | 示例 | 结果(假设 a=10, b=3) |
|---|---|---|---|
+ | 加法 | a + b | 13 |
- | 减法 | a - b | 7 |
* | 乘法 | a * b | 30 |
/ | 除法 | a / b | 3(注意!) |
% | 取模(求余数) | a % b | 1 |
最需要注意的就是除法 /。
两个整数相除,结果一定是整数,小数部分直接丢弃(不是四舍五入)。所以 10 / 3 得到 3,5 / 6 得到 0。要想得到小数结果,至少让其中一个操作数变成浮点数:
int a = 10, b = 3;
printf("%d\n", a / b); // 3
printf("%f\n", 10.0 / 3); // 3.333333
printf("%f\n", (double)a / b); // 3.333333
取模运算符 % 只能用于整数(C99 之前要求整数),结果是相除后的余数。取模的符号与被除数相同:-10 % 3 结果是 -1。
另外,C 语言没有幂运算符(^ 不是幂,是位运算),计算次方要用库函数 pow(在 <math.h> 里)。
二、赋值与复合赋值:让等号更强大
赋值运算符就是等号 =。它的意思是“把右边表达式的值,放进左边的变量里”。
int x;
x = 5 + 3; // x 变成 8
注意,等号不是数学里的“相等”,而是“赋予”。你可以连续赋值:
int a, b, c;
a = b = c = 0; // 从右往左,三个变量都变成 0
为了写起来更简洁,C 还提供了复合赋值运算符。它们把运算和赋值合二为一:
| 运算符 | 等价于 |
|---|---|
x += 5 | x = x + 5 |
x -= 5 | x = x - 5 |
x *= 5 | x = x * 5 |
x /= 5 | x = x / 5 |
x %= 5 | x = x % 5 |
后面的位运算也有对应的复合赋值(如 &=、|=、^= 等)。这些写法不光是少敲几个字,有时也能让编译器生成更高效的代码(特别是对早期编译器而言)。
三、自增自减:++ 和 --
++ 让变量加 1,-- 让变量减 1。它们既可以放在变量前面(前缀),也可以放在后面(后缀),但行为有微妙差别。
- 前缀:先加/减,再使用变量的值。
- 后缀:先使用变量的当前值,再加/减。
看例子:
int a = 5, b;
b = ++a; // 先 a 变成 6,再赋给 b,所以 b=6, a=6
int a = 5, b;
b = a++; // 先 b 取 a 的值 5,再 a 变成 6,所以 b=5, a=6
如果单独写一行 a++; 或 ++a;,效果一样。区别只在它们和“取值”动作合并在一个表达式里时才显现。
避坑指南:不要在一个表达式里多次修改同一个变量并取值,比如 c = a++ + ++a;,这种代码的结果是未定义的,不同编译器可能得出不同结果,绝不要这样写。
四、关系运算符:比大小,判真假
关系运算符用来比较两个值,结果是 1(真)或 0(假)。C 语言里没有真正的“布尔”类型(C99 有 _Bool,后面会提到),真假直接用整数表示。
| 运算符 | 含义 | 示例(a=5, b=3) | 结果 |
|---|---|---|---|
== | 等于 | a == b | 0 |
!= | 不等于 | a != b | 1 |
> | 大于 | a > b | 1 |
< | 小于 | a < b | 0 |
>= | 大于等于 | a >= 5 | 1 |
<= | 小于等于 | a <= 4 | 0 |
最常见的错误就是把相等写成 =(赋值)。if (a = 5) 永远为真,因为赋值表达式的值就是 5(非零即真),这会导致极难发现的逻辑 bug。比较相等务必用双等号 ==。
五、逻辑运算符:拼装条件
逻辑运算符用来连接多个关系表达式,构造复杂的判断条件。
| 运算符 | 含义 | 示例 | 结果 |
|---|---|---|---|
&& | 逻辑与(并且) | (a > 2) && (b < 10) | 两边都真才为真 |
| ` | ` | 逻辑或(或者) | |
! | 逻辑非(取反) | !(a > 2) | 真变假,假变真 |
逻辑运算符有一个非常重要的特性——短路求值:
- 对于
A && B,如果 A 已经是假,B 根本就不会计算。 - 对于
A || B,如果 A 已经是真,B 同样不会计算。
这个特性常常被用来安全地编写代码,比如:
int *p = NULL;
if (p != NULL && *p == 10) { // p 为空时不会去读 *p,避免了崩溃
printf("ok\n");
}
逻辑非 ! 可以把非零值变成 0,0 变成 1。!5 的结果是 0。
六、位运算符初探:直接玩转二进制
位运算符是对数据的二进制位进行操作的。它们是 C 语言高效和贴近硬件的体现,在嵌入式、系统编程和性能敏感的场景里非常有用。我们暂时只做感性了解,后面会有专门的文章深入。
| 运算符 | 含义 | 示例(a=5即0101,b=3即0011) | 结果 |
|---|---|---|---|
& | 按位与 | a & b (0101 & 0011) | 1 (0001) |
| ` | ` | 按位或 | `a |
^ | 按位异或 | a ^ b | 6 (0110) |
~ | 按位取反 | ~a | 取决于位数,对于8位是 11111010 |
<< | 左移 | a << 1 | 10 (1010) |
>> | 右移 | a >> 1 | 2 (0010) |
- 与
&:两位都是 1 结果才为 1,常用来“屏蔽”某些位。 - 或
|:任一位是 1 结果就为 1,用来“置位”。 - 异或
^:两位不同为 1,相同为 0,用于切换位或简单加密。 - 取反
~:所有位翻转,0 变 1,1 变 0。 - 移位:
<<左移一位相当于乘 2,>>右移一位相当于除 2(对正整数来说)。
注意:位运算符操作的是整型,不要弄混 & 和 &&、| 和 ||,它们是完全不同的东西。
七、其他你可能遇到的运算符
1. 条件运算符(三目运算符)
条件 ? 表达式1 : 表达式2 :如果条件为真,计算并返回表达式1,否则返回表达式2。
int max = (a > b) ? a : b;
它相当于 if-else 的简写形式,适合简单的二选一赋值。
2. 逗号运算符
, 可以连接多个表达式,整个表达式的值是最后一个表达式的值。它主要在 for 循环里用(后面会见到):
int x, y;
x = (y = 3, y + 2); // y 被赋为 3,然后 x 得到 5
日常写代码尽量不要滥用它,会让可读性变差。
3. sizeof 运算符
我们之前已经见过,用来获取类型或变量的大小,编译时计算。它也是运算符,不是函数。
八、运算符优先级与结合性速查
当你在一行里写多个运算符时,谁先算谁后算?规则就是优先级。如果优先级相同,结合性决定从左往右还是从右往左。
一个典型例子:a + b * c 先算 * 再算 +,因为乘除优先级高于加减。
优先级简表(从高到低,同一行优先级相同):
| 优先级 | 运算符 | 结合性 |
|---|---|---|
| 1 | () [] . -> | 左到右 |
| 2 | ! ~ ++ -- +(正) -(负) *(解引用) &(取地址) (类型) sizeof | 右到左 |
| 3 | * / % | 左到右 |
| 4 | + - | 左到右 |
| 5 | << >> | 左到右 |
| 6 | < <= > >= | 左到右 |
| 7 | == != | 左到右 |
| 8 | & (按位与) | 左到右 |
| 9 | ^ | 左到右 |
| 10 | ` | ` |
| 11 | && | 左到右 |
| 12 | ` | |
| 13 | ?: | 右到左 |
| 14 | = += -= 等 | 右到左 |
| 15 | , | 左到右 |
不用死记硬背,建议多用括号。括号的优先级最高,而且能让意图一目了然,比依赖默认优先级安全得多。
九、常见陷阱集合
-
整数除法截断
double half = 1 / 2;→half是 0.0。应改为1.0 / 2或强制类型转换。 -
把
==写成=
if (a = 5)恒为真。可以把常量写在左边:if (5 == a),这样如果漏写一个=会编译错误。 -
自增的副作用
int x = a++ + ++a;是未定义行为,不同编译器结果不同,绝不要写。 -
位运算与逻辑运算混淆
&和&&、|和||绝不等价。if (a & b)是按位与,如果 a 和 b 是 0 或 1 可能碰巧对,但多数情况下语义错误。 -
对浮点数用
%
3.14 % 2非法,取模只能用于整数。 -
优先级导致意外
*p++是*(p++)而不是(*p)++,因为后缀++优先级高于解引用*。同样,多用括号避免这类头疼问题。
十、小结
今天一口气认识了算术、赋值、自增自减、关系、逻辑、位运算、条件、逗号等 C 语言运算符,了解了优先级和结合性的基本规则。这些运算符就是程序的“动词”,它们决定了数据如何被操纵、条件如何判断、逻辑如何组织。
下一步,我们要用这些运算符来指挥程序的走向——分支结构来了。if、else、switch,让代码在不同条件下走不同的路,程序从此有了“判断力”。
课后小练习
- 写程序输入一个三位整数(比如 367),输出它的个位、十位、百位数字。提示:善用
/和%。 - 声明两个变量
a=10, b=20,通过加减法和异或运算两种方法,在不使用第三个变量的情况下交换它们的值,并打印交换前后的结果。 - 用条件运算符
?:实现:输入一个整数,输出它的绝对值。 - 试试写一行代码:
int x = 5; printf("%d\n", x++ + ++x);用不同编译器试试看结果是否一致?再决定永远不要写这样的代码。
我们下期见!
4938

被折叠的 条评论
为什么被折叠?



