一、算术操作符
+ - * / %
1. / (除号)
int i = 1 / 2; // i = 0 ; 除号两边都是整形,则得到的结果是自动去掉了小数点后面的数,得到的仅仅是整数部分
float j = 1.0 / 2; // i = 0.500000 除号两边只要有一个是小数,则结果就是小数(还要注意前面的类型要是浮点型,默认六位小数,要用%f 打印)
2. % (取模)
这个操作符的两边都要是整数才可以(关于负数取模可以在B站上找单个讲的《C语言深度解刨》
二、移位操作符
<<左移操作符 >>右移操作符
移动的是二进制位,整数的二进制表示有3种:原码、反码、补码
正数的原码、反码、补码相同;
负数的原码、反码、补码需要计算,
原码是用二进制来表示的整数(如果是32位操作系统就是32位,最高位是符号位)
整数在内存中存的是二进制补码的形式
如 7
原码:00000000000000000000000000000111(第一个0就是符号位,表示是正数,如果是1就是负数)
反码:00000000000000000000000000000111
补码:00000000000000000000000000000111
如 -7
原码:10000000000000000000000000000111
反码:111111111111111111111111111111111000(原码的符号位不变,其他位按位取反就是反码)
补码:111111111111111111111111111111111001 (反码+就是补码)
左移操作符:左边丢弃,右边补零
下边就是例子:a左移一位 int a = 7; int b = a << 1;b等于多少呢?
7的补码左移一位,最左边的丢弃,最右边少了一位补0,就得到: 00000000000000000000000000001110(补码)(反码)(原码)
将此原码转换为十进制数:14 即:b = 14
-7的补码左移一位,最左边的丢弃,最右边少了一位补0,就得到 111111111111111111111111111111110010(补码)
111111111111111111111111111111110001(反码:补码-1)
10000000000000000000000000001110(原码:反码符号位不变,其他位按位取反)
将此原码转换为十进制数:-14 即:b = -14
右移操作符:
1.算术移位:右边丢弃,左边补原符号位(通常编译器都是算术移位)
2.逻辑移位:右边丢弃,左边补0
下边是算数移位的例子:a右移一位 int a = 7; int c = a >> 1; c等于多少呢?
7的补码右移一位,最右边的丢弃,最左边少了一位补原符号位0,就得到: 00000000000000000000000000000011(补码)(反码)(原码)
将此原码转换为十进制数:3 即:c = 3
-7的补码右移一位,最右边的丢弃,最左边少了一位补原符号位1,就得到: 111111111111111111111111111111111100(补码)
111111111111111111111111111111111011(反码:补码-1)
10000000000000000000000000000100(原码:反码符号位不变,其他位按位取反)
将此原码转换为十进制数:-4 即:c = -4
三、位操作符
& 按(2进制)位与
| 按(2进制)位或
^ 按(2进制)位异或
-5的原码:10000000000000000000000000000101
-5的反码:111111111111111111111111111111111010
-5的补码:111111111111111111111111111111111011
3的补码:00000000000000000000000000000011
3 & -5:00000000000000000000000000000011(按位与就是补码对其,两个都是1才是1,否则为0)得到的是补码,转换成原码后,得出结果为:3
3 | -5:111111111111111111111111111111111011(按位或就是补码对其,两个都是0才是0,否则为1)得到的是补码,转换成原码后,得出结果为:-5
3 ^ -5:111111111111111111111111111111111000(按位异或就是补码对其,相同为0,相异为1) 得到的是补码,转换成原码后,得出结果为:-8
有什么用呢?
做一下这个题吧:不能创建临时变量(第三个变量),实现两个数的交换
1.创建临时变量,这种方法用的最多,运算效率最快
int r1 = 3;
int t1 = 5;
int m = 0;
printf("交换前:r1=%d t1=%d\n", r1, t1);
m = r1;
r1 = t1;
t1 = m;
printf("交换前:r1=%d t1=%d\n", r1, t1);
2.不创建临时变量,但可能存在栈溢出
int r2 = 3;
int t2 = 5;
printf("交换前:r2=%d t2=%d\n", r2, t2);
r2 = r2 + t2;
t2 = r2 - t2;
r2 = r2 - t2;
printf("交换前:r2=%d t2=%d\n", r2, t2);
3.不创建临时变量,且不用担心栈溢出
( // 首先要先了解^的特点
// 3^3 = 0 可以推出: a^a = 0
// ……011
// ……011
// ……000
//
// 0^5 = 5 可以推出: 0^a = a
// ……000
// ……101
// ……101
// 所以: 3^3^5 = 5
// 又因为:3^5^3 = 5(说明按位异或支持交换律)
)
int r3 = 3;
int t3 = 5;
printf("交换前:r3=%d t3=%d\n", r3, t3);
r3 = r3 ^ t3;
t3 = r3 ^ t3;
r3 = r3 ^ t3;
printf("交换后:r3=%d t3=%d\n", r3, t3);
四、赋值操作符
一个 = 是赋值操作符;注意两个 == 判断是否相等,一定要小心小心再小心
五、复合操作符
+= -= *= /= %= <<= >>= &= |= ^=