操作符分类
- 算术操作符 移位操作符 位操作符
- 赋值操作符 单目操作符 关系操作符
- 逻辑操作符 条件操作符 逗号表达式
- 下标引用、函数调用和结构成员
算数操作符
+ - * / %
对于+、-和*这三个算数操作符没什么好讲的,和小学数学里的一样。对于/和%这两个算数操作符,我们需要注意一下几个点:
1. 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。
2. 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。
3. % 操作符的两个操作数必须为整数。返回的是整除之后的余数。
4. 除法想得到小数的结果,必须保证除数和被除数中至少有一个小数(浮点数)。
5.0 / 2 = 2.5 //浮点数除法 2. 5 / 2 = 2 //整数除法
移位操作符
- << 左移操作符
- >> 右移操作符
注:移位操作符的操作数只能是整数,移动的是存储在内存中的补码。
学习左移操作符之前,我们需要知道数据的二进制的表现形式。二进制有三种表现形式,分别是原码,反码和补码。原码、反码和补码都是有符号位和数值位组成。计算机存储的是数据的原码,打印数据的时候需要数据的补码转换成原码再打印输出 。注意:正整数的原码、反码和补码是相同的,而原码就是直接将十进制的数字转换成二进制就行了。而负整数的反码是在原码的基础上,除了符号位,其他位按位取反,而反码再加上一就等到了负整数的补码了。
例子:
1.左移操作符
移位规则:
左边抛弃、右边补0
代码示例:
#include <stdio.h> int main() { int num = 10; num << 1; printf("num = %d\n", num); return 0; }
输出结果:
代码示例:
#include <stdio.h> int main() { int num = 10; num = num << 1; //可简化为num <<= 1; printf("num = %d\n", num); return 0; }
输出结果:
注意:将一个数左移n位得到的结果等于原来的数乘上2的n次方得到的结果。 比如:将10左移3位,得到的结果就是80。
2.右移操作符
移位规则
1. 首先右移运算分两种: 2. 1. 逻辑移位 3. 左边用0填充,右边丢弃 4. 2. 算术移位 5. 左边用原该值的符号位填充,右边丢弃
注意:C语言并未规定,右移操作符是逻辑右移还是算数右移,这取决于编译器,绝大多数的编译器是算数右移。
代码示例:
#include <stdio.h> int main() { int num = 16; num >>= 1; printf("num = %d\n", num); return 0; }
输出结果:
如果将num右移n位,且num和2的n次方成倍数关系,那么num右移n位得到结果就是num除以2的n次方得到的结果。但是如果不成倍数关系的话,就要写成补码形式右移n为,再转成原码的形式计算出该数的大小。
例子:
注意:对于移位运算符,不要移动负数位,这个是标准未定义的。
1. int num = 10; 2. num>>-1;//error
位操作符
1. & //按位与 2. | //按位或 3. ^ //按位异或 4. 注:它们的操作数必须是整数。
真值表
1.位操作符的特点
&按位与: 两个数的补码对应位都为1,得到的结果才为1,否则结果就为0。
| 按位或: 两个数的补码对应位有一个为1,得到的结果就为1,否则结果就位0。
^按位异或:两个数的补码对应位不同,得到的结果为1,否则结果就为0。特例:两个
相同的数按位异或得到的结果为0,一个数与0按位异或得到结果为它本身。
代码示例:
#include <stdio.h> int main() { int a = 10; int b = 20; int c = a & b; printf("%d\n", c); return 0; }
输出结果:
代码示例:
#include <stdio.h> int main() { int a = 10; int b = 20; int c = a | b; printf("%d\n", c); return 0; }
输出结果:
代码示例:
#include <stdio.h> int main() { int a = 10; int b = 20; int c = a | b; printf("%d\n", c); return 0; }
输出结果:
2.一道巧妙的笔试题
不能创建临时变量(第三个变量),实现两个数的交换。
代码示例:
#include <stdio.h> int main() { int a = 10; int b = 20; a = a + b; b = a - b; a = a - b; printf("a=%d b=%d\n", a, b); return 0; }
输出结果:
这种方法有一点小问题:如果a和b的值非常大,a+b相加后超出整型的取值范围,将会出现错误。不过还有一种方法能够实现两个数的交换,而已不会出现上述的问题。
代码示例:
#include <stdio.h> int main() { int a = 10; int b = 20; a = a ^ b; b = a ^ b; a = a ^ b; printf("a=%d b=%d\n", a, b); return 0; }
输出结果:
3.三道重要的练习题
编写代码实现:求一个整数存储在内存中的二进制中1的个数。
代码示例:
#include <stdio.h> int main() { //本题相当于进制转换 int n = 0; int sum = 0; scanf("%d", &n); while (n) { //15 7 3 1 if (n % 2 == 1) { sum++; } n /= 2; } printf("%d\n", sum); return 0; }
注意:上面的代码只能求正数的补码有多少个一,不能求负数的补码有多少个一。但是这种方法的思路非常重要,可以用于进制转换。
代码示例:
#include <stdio.h> int main() { int count = 32; int n = 0; int sum = 0; scanf("%d", &n); //一个整型变量占32个比特位 while (count) { if (n & 1 == 1) { sum++; } n >>= 1; count--; } printf("%d\n", sum); return 0; }
输出结果:
代码示例:
#include <stdio.h> int main() { int num = 0; scanf("%d", &num); int count = 0;//计数 while (num) { count++; num = num & (num - 1); } printf("%d\n", count); return 0; }
输出结果:
求两个数二进制中不同位的个数
代码示例:
//求两个数二进制中不同位的个数 #include <stdio.h> int main() { int m = 0; int n = 0; int sum = 0;//计数器 scanf("%d%d", &m, &n); int ret = m ^ n;//借助异或来求,相同为0,不相同为1 int count = 32; while (count) { if (ret & 1 == 1)//符合条件的说明ret的最低位为1,也就是说明m和n有一个不同位 { sum++; } count--; ret >>= 1;//ret右移一位 } printf("%d", sum); return 0; }
//求两个数二进制中不同位的个数 #include <stdio.h> int main() { int m = 0; int n = 0; int count = 0;//计数器 scanf("%d%d", &m, &n); int tmp = m ^ n;//借助异或来求,相同为0,不相同为1 while (tmp) { tmp = tmp & (tmp - 1); count++; } printf("%d", count); return 0; }
获取一个整数二进制序列中所有的偶数位和奇数位,分别打印出二进制序列。
代码示例:
#include <stdio.h> int main() { //00000000000000000000000000001010 ->10的补码 //偶数位数字0000000000000011 //奇数位数字0000000000000000 int i = 0; int n = 0; scanf("%d", &n); for (i = 31; i >= 0; i -= 2) { //打印偶数位上的数字 printf("%d", (n >> (i)) & 1); } printf("\n"); for (i = 30; i >= 0; i -= 2) { //打印奇数位上的数字 printf("%d", (n >> (i)) & 1); } printf("\n"); return 0; }
输出结果: