1. 操作符分类
算术操作符
移位操作符
位操作符
赋值操作符
单目操作符
关系操作符
逻辑操作符
条件操作符
逗号表达式
下标引用、函数调用和结构成员
2. 算术操作符
+, -, * , / ,%
除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。
对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。
% 操作符的两个操作数必须为整数。返回的是整除之后的余数。
#include <stdio.h> int main() { // / 除法 - 得到的是商 // 除法操作符的两个操作数都是整数的话,执行的是整数除法 // 除法操作符的两个操作数只要有一个浮点数,执行的是小数除法 // // % 取模( 取余)得到的是余数 // 取模操作符的操作数必须是整数 printf("%lf\n", 10 / 3.0);//5 printf("%d\n", 10 % 2);//0 return 0; }
3. 移位操作符
左移操作符<<
右移操作符>>
注:移位操作符的操作数只能是整数。
3.1 整数的二进制是怎么形成的
整数的二进制表示形式有三种:原码,反码,补码
原码:把一个数按照正负直接翻译成二进制就是原码
反码:原码的符号位不变,其他位按位取反就是反码
补码:反码+1
注意:
正整数的原码,反码,补码是相同的
负整数的原码,反码,补码是要计算的
最高的一位表示符号位,0表示正数,1表示负数
整数在内存中储存的是补码(二进制)
原码到补码是取反+1,补码到原码是取反+1或-1取反。
3.2 左移操作符
移位规则:
左边抛弃、右边补0
int main() { int a = -3; //10000000000000000000000000000011 //11111111111111111111111111111100 //11111111111111111111111111111101 - 补码 // int b = a << 1; //11111111111111111111111111111010 //11111111111111111111111111111001 //10000000000000000000000000000110 //11111111111111111111111111111010 //10000000000000000000000000000101 //10000000000000000000000000000110 printf("%d\n", b);//-6 printf("%d\n", a);//-3 return 0; }
3.3 右移操作符
移位规则:
首先右移运算分两种:
逻辑移位
左边用0填充,右边丢弃
算术移位
左边用原该值的符号位填充,右边丢弃
右移的时候,到底采用的是算数右移还是逻辑右移,是取决于编译器的!
//>> 右移操作符 //VS:算术右移 int main() { int a = -5; //10000000000000000000000000000101 //11111111111111111111111111111010 //11111111111111111111111111111011 // int b = a >> 1; //11111111111111111111111111111101 //11111111111111111111111111111100 //10000000000000000000000000000011 //-3 printf("b = %d\n", b); printf("a = %d\n", a);//-5 return 0; }
警告⚠:
对于移位运算符,不要移动负数位,这个是标准未定义的。
例如:
int num = 10; num>>-1;//error
4. 位操作符
位操作符有:
& 按位与
| 按位或
^ 按位异或
注:他们的操作数必须是整数。
int main() { int a = 3; int b = -5; int c = a ^ b;//按位异或 - 对应的二进制位,相同为0,相异为1 //11111111111111111111111111111011 - -5的补码 //00000000000000000000000000000011 - 3的补码 //11111111111111111111111111111000 //11111111111111111111111111110111 //10000000000000000000000000001000 - 结果为-8 int c = a | b;//按位或 - 有1则是1 //11111111111111111111111111111011 - -5的补码 //00000000000000000000000000000011 - 3的补码 //11111111111111111111111111111011 - 结果为-5 int c = a & b;//按位与 - 两个都是1,结果才为1 //00000000000000000000000000000011 - 3的补码 //10000000000000000000000000000101 - 5的原码 //11111111111111111111111111111010 //11111111111111111111111111111011 - -5的补码 //00000000000000000000000000000011 - 3的补码 //00000000000000000000000000000011 - 结果为3 printf("%d\n", c); return 0; }
一道变态的面试题:
编写代码实现:不能创建临时变量(第三个变量),实现两个数的交换。
int main() //三种方法,其中第三种是不需要临时变量的 { int a = 3; int b = 5; //int tmp = 0; printf("交换前:a=%d b=%d\n", a, b); //3 //a = a ^ b; //b = a ^ b; //a = a ^ b; //2 /*a = a + b; b = a - b; a = a - b;*/ //1 //tmp = a; //a = b; //b = tmp; printf("交换后:a=%d b=%d\n", a, b); return 0; }
练习:
编写代码实现:求一个整数存储在内存中的二进制中1的个数。
int main() //思路 { int a = 11; a & 1; a = a >> 1; //00000000000000000000000000001011 //00000000000000000000000000000001 //00000000000000000000000000000001 return 0; } //方法1 #include <stdio.h> int main() { int num = 10; int count = 0;//计数 while (num) { if (num % 2 == 1) count++; num = num / 2; } printf("二进制中1的个数 = %d\n", count); return 0; } //思考这样的实现方式有没有问题? //方法2: #include <stdio.h> int main() { int num = -1; int i = 0; int count = 0;//计数 for (i = 0; i < 32; i++) { if (num & (1 << i)) count++; } printf("二进制中1的个数 = %d\n", count); return 0; } //思考还能不能更加优化,这里必须循环32次的。 //方法3: #include <stdio.h> int main() { int num = -1; int i = 0; int count = 0;//计数 while (num) { count++; num = num & (num - 1); } printf("二进制中1的个数 = %d\n", count); return 0; } //这种方式是不是很好?达到了优化的效果,但是难以想到。