1. 操作符分类:
算术操作符
移位操作符
位操作符
赋值操作符
单目操作符
关系操作符
逻辑操作符
条件操作符
逗号表达式
下标引用、函数调用和结构成员
2. 算术操作符
+ - * / %
1. 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。
2. 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。
3. % 操作符的两个操作数必须为整数。返回的是整除之后的余数。
3. 移位操作符
1. << 左移操作符 2. >> 右移操作符 3. 注:移位操作符的操作数只能是整数。
3.1 左移操作符
移位规则:
左边抛弃、右边补0
3.2 右移操作符
移位规则:
首先右移运算分两种:
1. 逻辑移位
左边用0填充,右边丢弃
2. 算术移位
左边用原该值的符号位填充,右边丢弃
警告⚠:
对于移位运算符,不要移动负数位,这个是标准未定义的。
例如:
1. int num = 10; 2. num>>-1;//error
4. 位操作符
先来说明一下:在计算机中存储的信息均是以二进制形式保存的。且数字是以补码形式保存的,正数的补码和原码同,负数的补码为原码取反后加1。
位操作符有:
1. & //按位与 2. | //按位或 3. ^ //按位异或 4. 注:他们的操作数必须是整数。
4.1 按位与运算符(&)
参加运算的两个数据,按二进制位进行“与”运算。
运算规则:0&0=0; 0&1=0; 1&0=0; 1&1=1;
即:两位同时为“1”,结果才为“1”,否则为0 (和逻辑运算符 && 与类似的功能)
例如:3&5 即 0000 0011 & 0000 0101 = 0000 0001 因此,3&5的值得1。
负数按补码形式参加按位与运算。(正数其实也是按补码进行计算,计算机中都是按补码进行计算,只不过正数的原码反码补码相同)
4.2 按位或运算符(|)
参加运算的两个对象,按二进制位进行“或”运算。
运算规则:0|0=0; 0|1=1; 1|0=1; 1|1=1;
即 :参加运算的两个对象只要有一个为1,其值为1。 (可对等逻辑预算符 || 有一个为true则为true)
例如:3|5 即 0000 0011 | 0000 0101 = 0000 0111 因此,3|5的值得7。
另,负数按补码形式参加按位或运算。
4.3 异或运算符符(^)
参加运算的两个数据,按二进制位进行“异或”运算。
运算规则:0^0=0; 0^1=1; 1^0=1; 1^1=0;
即:参加运算的两个对象,如果两个相应位为“异”(值不同),则该位结果为1,否则为0。
练习一下:
1. #include <stdio.h> 2. int main() 3. { 4. int num1 = 1; 5. int num2 = 2; 6. num1 & num2; 7. num1 | num2; 8. num1 ^ num2; 9. return 0; 10. }
一道变态的面试题:
不能创建临时变量(第三个变量),实现两个数的交换
1. #include <stdio.h> 2. int main() 3. { 4. int a = 10; 5. int b = 20; 6. a = a^b; 7. b = a^b; 8. a = a^b; 9. printf("a = %d b = %d\n", a, b); 10. return 0; 11. }
练习:
编写代码实现:求一个整数存储在内存中的二进制中1的个数。
1. //方法1 2. #include <stdio.h> 3. int main() 4. { 5. int num = 10; 6. 7. int count = 0;//计数 8. while (num) 9. { 10. if (num % 2 == 1) 11. count++; 12. num = num / 2; 13. } 14. printf("二进制中1的个数 = %d\n", count); 15. return 0; 16. } 17. //思考这样的实现方式有没有问题? 18. //方法2: 19. #include <stdio.h> 20. int main() 21. { 22. int num = -1; 23. int i = 0; 24. int count = 0;//计数 25. for (i = 0; i < 32; i++) 26. { 27. if (num & (1 << i)) 28. count++; 29. } 30. printf("二进制中1的个数 = %d\n", count); 31. return 0; 32. } 33. //思考还能不能更加优化,这里必须循环32次的。 34. //方法3: 35. #include <stdio.h> 36. int main() 37. { 38. int num = -1; 39. int i = 0; 40. int count = 0;//计数 41. while (num) 42. { 43. count++; 44. num = num & (num - 1); 45. } 46. printf("二进制中1的个数 = %d\n", count); 47. return 0; 48. } 49. //这种方式是不是很好?达到了优化的效果,但是难以想到
5. 赋值操作符
赋值操作符是一个很棒的操作符,他可以让你得到一个你之前不满意的值。也就是你可以给自己重新赋值。
1. int weight = 120;//体重 2. weight = 89;//不满意就赋值 3. double salary = 10000.0; 4. salary = 20000.0;//使用赋值操作符赋值。 5. 6. 赋值操作符可以连续使用,比如: 7. int a = 10; 8. int x = 0; 9. int y = 20; 10. a = x = y+1;//连续赋值 11. 这样的代码感觉怎么样? 12. 那同样的语义,你看看: 13. x = y+1; 14. a = x; 15. 这样的写法是不是更加清晰爽朗而且易于调试。
复合赋值符
1. += 2. -= 3. *= 4. /= 5. %= 6. >>= 7. <<= 8. &= 9. |= 10. ^=
这些运算符都可以写成复合的效果。
比如:
1. int x = 10; 2. x = x+10; 3. x += 10;//复合赋值 4. //其他运算符一样的道理。这样写更加简洁
6. 单目操作符
6.1 单目操作符介绍
1. ! 逻辑反操作 2. - 负值 3. + 正值 4. & 取地址 5. sizeof 操作数的类型长度(以字节为单位) 6. ~ 对一个数的二进制按位取反 7. -- 前置、后置-- 8. ++ 前置、后置++ 9. * 间接访问操作符(解引用操作符) 10. (类型) 强制类型转换
演示代码:
1. #include <stdio.h> 2. int main() 3. { 4. int a = -10; 5. int* p = NULL; 6. printf("%d\n", !2); 7. printf("%d\n", !0); 8. a = -a; 9. p = &a; 10. printf("%d\n", sizeof(a)); 11. printf("%d\n", sizeof(int)); 12. printf("%d\n", sizeof a);//这样写行不行? 13. printf("%d\n", sizeof int);//这样写行不行? 14. return 0; 15. }
关于sizeof其实我们之前已经见过了,可以求变量(类型)所占空间的大小,,所以报错的地方的int加一个()就可以了。