整理出了个人觉得操作符中容易出错或者需要多加注意的知识点
算术操作符(+ - * / %)
- 除%外,其余的几个算术操作符都可以作用于整数和浮点数
- 如果 / 两边的操作数都为整数,那么就执行整数除法;如果 / 两边至少有一边的操作数是浮点数,那么就执行浮点数除法。
int a = 6 / 5; //得到结果为2
int b = 1 / 2; //得到结果为 0
double c = 6.0 / 5; //得到结果为1.200000
double c = 6 / 5.0; //得到结果为1.200000
- %操作符两边的操作数必须为整数
移位操作符(>> <<)
<< 左移操作符
>> 右移操作符
#include <stdio.h> int main() { int a = 2; //左移操作符,把a的二进制位向左移动一位 int b = a << 1; printf("%d\n", b); return 0; }
得到的结果为: 4
右移a完成后赋值给b,a本身的值并未改变。
其中a的数据类型为int型,在VS2019编译器下占用4个字节,即32个比特位。
左移操作符:
左边丢弃,右边补0
右移操作符:
1.算术右移
右边丢弃,左边补原符号位(整数补0,负数补1)
2.逻辑右移
右边丢弃,左边补0
整数的二进制表示形式:原码、反码和补码。
对于负整数来说:
原码:直接根据数值写出的二进制序列就是原码
反码:原码的符号位不变,其他位按位取反就是反码
补码:在反码的基础上+1,就是补码
对于正整数来说:
原码、反码、补码都相同
负数:-1
存放在内存中
存放的是二进制的补码
原码:10000000000000000000000000000001
反码:11111111111111111111111111111110
补码:11111111111111111111111111111111
位操作符(& | ^)
& --按(二进制)位与
| --按(二进制)位或
^ --按(二进制)位异或
注:操作数都为整数
&(按位与)
计算规则:按二进制位对比,两边都为1时才为1,其余为0.
例如:
#include <stdio.h> int main() { int x = 3; int y = 5; //x 在内存中表示为:00000000000000000000000000000011 (32个比特位) //y 在内存中表示为:00000000000000000000000000000101 int z = x & y; //x:00000000000000000000000000000011 //y:00000000000000000000000000000101 //z:00000000000000000000000000000001 //故z的值应为1 printf("%d\n", z); return 0; }
运行结果为:
| (按位或)
计算规则:按二进制位对比,只要有一位是1就为1,其余为0 .
例如:
#include <stdio.h> int main() { int x = 3; int y = 5; //x 在内存中表示为:00000000000000000000000000000011 (32个比特位) //y 在内存中表示为:00000000000000000000000000000101 int z = x | y; //x:00000000000000000000000000000011 //y:00000000000000000000000000000101 //z:00000000000000000000000000000111 //故z的值应为7 printf("%d\n", z); return 0; }
运行结果为:
^ (按位异或)
计算规则为:按二进制位对比,相同的则为0,不同的则为1.
例如:
#include <stdio.h> int main() { int x = 3; int y = 5; //x 在内存中表示为:00000000000000000000000000000011 (32个比特位) //y 在内存中表示为:00000000000000000000000000000101 int z = x ^ y; //x:00000000000000000000000000000011 //y:00000000000000000000000000000101 //z:00000000000000000000000000000110 //故z的值应为6 printf("%d\n", z); return 0; }
运行结果为:
例题1:有两个变量a = 3,b = 5;在不使用第三个变量的情况下交换另个变量的值,即a = 5,b = 3.
第一种方法(不足):
#include <stdio.h> int main() { //缺点:如果数值过大,则会溢出 int a = 3; int b = 5; printf("a = %d\nb = %d\n\n", a, b); a = a + b; b = a - b; a = a - b; printf("a = %d\nb = %d\n", a, b); return 0; }
第二种方法(位操作符的知识点):
#include <stdio.h> int main() { int a = 3; int b = 5; printf("a = %d\nb = %d\n\n", a, b); a = a ^ b; // a:00000000000000000000000000000011 // b:00000000000000000000000000000101 //a = a ^ b :00000000000000000000000000000110 //此时a的值为6 b = a ^ b; // a :00000000000000000000000000000110 // b :00000000000000000000000000000101 //b = a ^ b : 00000000000000000000000000000011 //此时b的值为3 a = a ^ b; // a :00000000000000000000000000000110 // b : 00000000000000000000000000000011 //a = a ^ b : 00000000000000000000000000000101 //此时a的值为5 printf("a = %d\nb = %d\n", a, b); //故实现了a和b的值互换 return 0; }
异或的计算法则:
存在一个变量a
一、a ^ a = 0 ,即一个数异或它本身,得到的结果为0。
二、0 ^ a = a ,即一个数异或0,得到的结果为它本身。
所以,之前所用的第二个方法的底层逻辑是:
a = a ^ b;
b = a ^ b; 一、b这里异或得到的值就是旧的a的值
a = a ^ b; 二、a这里异或得到的值就是旧的b的值
一处可以等价于
b = a ^ (b ^ b)
即 b = a ^ 0 = a = 3
二处可以等价于
a = (a ^ a) ^ b
即 a = 0 ^ b = 5
思考题:编写代码,求一个整数存储在内存中的二进制中1的个数
赋值操作符(= += -= *= /= %= >>= <<=)
- 赋值操作符可以连续使用,为右结合性
例如:
#include <stdio.h> int main() { int a = 0; int x = 10; int y = 20; a = x = y + 9; printf("a = %d\nx = %d\ny = %d\n", a, x, y); return 0; }
运行结果为:
但更建议拆开来写,即x = y + 9,a = x。
如此便更加清晰明朗,且易于调试。
单目操作符(! - + & sizeof ~ -- ++ * (类型) )
sizeof
- sizeof计算数组的大小
int arr[ 10 ] = { 0 };
sizeof(arr) 或sizeof(int [ 10 ]) 两种都是可行的
- sizeof括号中的表达式是不参与运算的
例如:
#include <stdio.h> int main() { short a = 5; int b = 10; printf("%d\n", sizeof(a += b)); //这里a被赋值为15,但并不参与运算 printf("%d\n", a); //故打印出的a值依旧为5 return 0; }
运行结果为:
C语言学习记录——操作符详解知识点选记(算术操作符、单目操作符、移位操作符、关系操作符、逻辑操作符、条件操作符......)二:https://developer.aliyun.com/article/1530373