C语言从入门到进阶——第10讲:操作符详解
这一讲我们系统地把 C 语言中所有的操作符(运算符)过一遍,重点解决三个核心问题:
- 操作符到底分哪几类?每类有什么坑?
- 优先级和结合性到底怎么记?(最容易出错的地方)
- 常见陷阱 + 经典面试/笔试题型
一、C语言操作符完整分类(15种大类)
| 优先级级别 | 类别 | 主要操作符 | 结合性 | 备注 / 常见坑点 |
|---|---|---|---|---|
| 1 | 后缀(最高) | () 函数调用、[] 数组下标、.、->、后置++/-- | 左→右 | 后置 ++/– 先用值再自增/减 |
| 2 | 前缀/单目 | 前置++/--、+ - ! ~ * & sizeof (类型)强制转换 | 右←左 | 单目几乎全右结合;sizeof 是运算符不是函数 |
| 3 | 乘除取模 | * / % | 左→右 | 整数 / 和 % 向零截断;负数 % 实现定义 |
| 4 | 加减 | + - | 左→右 | 指针 + 整数 → 指针移动 |
| 5 | 移位 | << >> | 左→右 | 右移有符号数 → 算术右移(符号位保留) |
| 6 | 关系 | < <= > >= | 左→右 | 不要写 a < b < c(链式求值有坑) |
| 7 | 相等性 | == != | 左→右 | 浮点数慎用 == |
| 8 | 按位与 | & | 左→右 | |
| 9 | 按位异或 | ^ | 左→右 | |
| 10 | 按位或 | | | 左→右 | |
| 11 | 逻辑与 | && | 左→右 | 短路求值 |
| 12 | 逻辑或 | || | 左→右 | 短路求值 |
| 13 | 条件(三目) | ?: | 右←左 | 唯一的三目运算符,右结合 |
| 14 | 赋值及复合赋值 | = += -= *= /= %= <<= >>= &= ^= |= | 右←左 | 复合赋值优先级很低 |
| 15(最低) | 逗号 | , | 左→右 | 整个逗号表达式值 = 最后一个表达式的值 |
最重要记忆口诀(面试/写代码必背):
- 优先级从高到低粗记:
后缀 > 单目前缀 > 乘除模 > 加减 > 移位 > 关系 > 相等 > 位与 ^ | > 逻辑与或 > 三目 > 赋值 > 逗号 - 结合性只有三类右结合(其余全左结合):
- 所有单目前缀运算符
- 三目条件运算符
?: - 所有赋值运算符(包括复合赋值)
二、常见操作符行为详解 + 坑点
- 算术操作符
/整数除法 → 向零截断(C99 起标准统一)c -7 / 3 = -2 // 不是 -3! -7 % 3 = -1 // 符号跟被除数(左操作数)走(实现定义,但主流编译器如此)
- 自增/自减(最容易错)
int i = 5;
int a = i++; // a=5, i=6
int b = ++i; // i=7, b=7
// 经典错题
i = 1;
i = i++ + ++i; // 未定义行为!不同编译器结果不同(3、4、5 都有可能)
- 逻辑运算符短路
if (p && *p > 0) // 如果 p==NULL,后面的 *p 不会执行 → 安全
- 位运算经典用法
- 取某位:
(n >> k) & 1 - 清零某位:
n &= ~(1 << k) - 最低位1清零:
n &= (n-1)
- 逗号表达式
a = 1, b = 2, c = 3; // a=1, b=2, c=3,整个表达式值为 3
三、优先级 + 结合性经典面试/笔试题
// 1
int i = 1;
int x = i++ + i++; // 未定义行为!不要写
// 2
int a = 2;
int b = a += a *= a; // 先 a*=a → a=4,再 a+=4 → a=8,b=8(右结合)
// 3
int n = 1;
n = n++ + ++n + n++; // 未定义行为!千万别写
// 4 (很经典)
int x = 5;
printf("%d\n", x+++x); // 后置++ 先用值,所以 5 + 6 = 11(但严格说有歧义,建议加括号)
// 5
int a=1, b=2, c=3;
printf("%d\n", a+=b+=c); // 从右结合:b+=3 → b=5,a+=5 → a=6,打印 6
四、写代码时的“保命”习惯(强烈建议养成)
- 多加括号 —— 永远不要依赖记忆优先级
// 推荐写成
if ((a & b) != 0 && x > y)
// 而不是靠脑子记 & 比 != 高
- 禁止写 a++ + ++a / a += b += c 等未定义或实现定义行为
- 关系/相等不要链式写
// 错: if (1 < a < 10) // 实际是 (1 < a) < 10 → 0或1
// 对: if (1 < a && a < 10)
- 浮点数不要用 == 判断相等,用 fabs(a-b) < 1e-6
小结一句话
操作符的核心就是“优先级 + 结合性 + 副作用顺序 + 未定义行为”四个雷区。
优先级和结合性用表格死记 + 多加括号;副作用顺序和未定义行为靠经验避坑。
下一讲想重点看哪个方向?
- 位运算的进阶玩法(位段、掩码、位域等)
- 指针与操作符的结合(p++ / ++p / (*p)++ 等恶心写法)
- 表达式求值顺序与未定义行为深度剖析
- 或者直接来 20 道操作符相关的经典笔试题刷一波?
告诉我你的需求~