C语言学习笔记(第8章)—— 位运算符 + ++ / — 自增自减运算符
建议收藏 + 手敲所有例子,这章内容是面试、嵌入式、算法竞赛的“必杀技”!
一、位运算符(6个,全部掌握)
| 运算符 | 名称 | 示例 | 功能说明 | 经典用途 |
|---|---|---|---|---|
& | 按位与 | a & b | 对应位都为1才为1 | 取特定位、判断奇偶、掩码 |
| | 按位或 | a | b | 对应位有一个1就为1 | 设置特定位 |
^ | 按位异或 | a ^ b | 对应位不同为1,相同为0 | 交换两数、加密、找只出现一次的数 |
~ | 按位取反 | ~a | 所有位翻转(0变1,1变0) | 快速得到全1掩码 |
<< | 左移 | a << n | 所有位左移n位,低位补0 | 快速乘2、构造大数 |
>> | 右移 | a >> n | 有符号右移(带符号位扩展) 无符号右移(补0) | 快速除2、提取高位 |
1. 位运算核心规律(背下来一辈子受用)
a ^ a = 0
a ^ 0 = a
a & 0 = 0
a & -1 = a // -1 的补码是全1
a | 0 = a
a | -1 = -1
~0 = -1
~(-1) = 0
2. 神级应用案例(面试手撕必备)
// 1. 不使用临时变量交换两个数(异或三连)
a = a ^ b;
b = a ^ b; // b = (a^b)^b = a
a = a ^ b; // a = (a^b)^a = b
// 2. 判断一个数是否是2的幂(只有一个1)
n > 0 && (n & (n-1)) == 0
// 3. 找出数组中只出现一次的数字(其他都出现两次)
int singleNumber(int* nums, int size) {
int res = 0;
for(int i = 0; i < size; i++) {
res ^= nums[i]; // 成对的都变成0,剩下的就是答案
}
return res;
}
// 4. 不用数学运算实现加法(位运算模拟)
int add(int a, int b) {
while(b != 0) {
int carry = (a & b) << 1; // 进位
a = a ^ b; // 不带进位的和
b = carry;
}
return a;
}
3. 位移运算技巧(快如闪电)
x << 1 = x * 2
x << 2 = x * 4
x << 3 = x * 8
x >> 1 = x / 2 (对正数成立,对负数取决于实现)
#define SET_BIT(x, n) (x |= (1 << n)) // 把第n位置1
#define CLR_BIT(x, n) (x &= ~(1 << n)) // 把第n位清0
#define TOG_BIT(x, n) (x ^= (1 << n)) // 第n位取反
#define GET_BIT(x, n) ((x >> n) & 1) // 取第n位
二、++ 和 — 自增自减运算符(最容易写错的地方)
| 运算符 | 名称 | 用法示例 | 值 | 副作用(变量最终值) |
|---|---|---|---|---|
++i | 前置自增 | j = ++i; | 先加后用 | i = i + 1 |
i++ | 后置自增 | j = i++; | 先用后加 | i = i + 1 |
--i | 前置自减 | j = --i; | 先减后用 | i = i – 1 |
i-- | 后置自减 | j = i--; | 先用后减 | i = i – 1 |
经典陷阱题(99%的人第一次都错)
int i = 5;
printf("%d\n", i++); // 输出 5,i变成6
printf("%d\n", ++i); // 输出 7,i变成7
int a = 1;
int b = a++ + a++; // 未定义行为!(Undefined Behavior)
printf("%d\n", b); // 可能是 3、4、5,编译器说了算!
int x = 1;
int y = x++ + ++x; // 未定义行为!不要写这种代码!
铁律:永远不要在一句话里对同一个变量使用多次 ++/–
推荐写法(清晰无歧义)
i++; // 单独一行,最清晰
++i;
i = i + 1; // 某些情况下更直观
i += 1;
for(int i = 0; i < 10; i++) { } // 经典用法,没问题
三、总结口诀(背会直接升段)
位运算口诀:
- 与0清,与1保,异或换,取反最逍遥
- 左移乘以2,右移除以2,1左移n位就是2的n次方
自增自减口诀:
- 前++先加后用,后++先用后加
- 一句话里别把同一个变量++两次,写错就爆炸!
终极练习题(建议手敲)
// 1. 不用循环打印一个整数的二进制(位运算)
void print_binary(unsigned int n) {
for(int i = 31; i >= 0; i--) {
putchar((n >> i) & 1 ? '1' : '0');
}
putchar('\n');
}
// 2. 计算一个整数中有多少个1(布赖恩·克尼根算法)
int count_one_bits(unsigned int n) {
int cnt = 0;
while(n) {
n &= (n - 1); // 每次消掉最右边的1
cnt++;
}
return cnt;
}
掌握了本章内容,你就已经超越了 80% 的 C 语言初学者!
下一章预告:指针(真正的灵魂所在),准备好了吗?
需要我出「位运算 + 自增自减 100题PDF」或者「嵌入式位操作实战手册」,直接说一声!