目录
- 算术操作符
- 移位操作符
- 右移操作符
- 左移操作符
- 位操作符
- & 按位与
- | 按位或
- ^ 按位异或
- 赋值操作符
- 单目操作符
- !逻辑取反
- + –
- & *
- sizeof
- ~ 按位取反
- ++ 和 – –
- 关系操作符
- 逻辑操作符
- 条件操作符
- 逗号表达式
- 下标引用、函数调用和结构成员
算术操作符
+ - * / %
1.对于 / 操作符,如果两个操作数都是整数,执行整数除法;只要有一边是浮点数就是浮点数的除法。
2.操作符 % 为取余,两边的数必须都是整数,不能为浮点数。剩下的几个操作符都可以作用于整数和浮点数。
移位操作符
<< 左移操作符>> 右移操作符
1.操作数只能是整数
2.移动的是二进制
计算机中都是由二进制表示信息的,整数二进制有三种表示形式:原码、反码、补码
1.正整数的原码、反码、补码都是相同的
2.负整数的原码、反码、补码需要计算
1.无论该整数是正的还是负的都可以写出原码:根据正负直接写出的二进制序列就是原码。
2.十进制到二进制的转化方法:除2取余,逆序排列。
假如我们这里给个 int a = 15,15的二进制是1111,一个整型占4个字节,也就是32位,所以前28位都是0。二进制第一位是符号位,0为正,1为负。
int a = 15;// 0000 0000 0000 0000 0000 0000 0000 1111 原码// 0000 0000 0000 0000 0000 0000 0000 1111 反码// 0000 0000 0000 0000 0000 0000 0000 1111 补码
int a = -15;// 1000 0000 0000 0000 0000 0000 0000 1111 原码// 1111 1111 1111 1111 1111 1111 1111 0000 反码(符号位不变,按位取反)// 1111 1111 1111 1111 1111 1111 1111 0001 补码(按位取反,末位加1(反码加1)/从右往左遇见的第一个1不变,前面按位取反)
整数在计算机内存中存储的是补码,计算的时候使用补码计算。
所以移位移动的是二进制序列的补码
#includeint main(){int a = 15;int b = a >> 1; //右移printf("%d\n", b);return 0;}
右移操作符
右移运算分为两种:逻辑右移(右边丢弃,左边补0);算术右移(右边丢弃,左边补符号位)
左移操作符
左边丢弃,右边补0
不要移动负数位,标准未定义
位操作符
与移位操作符一样都是操作二进制
位操作符的操作数必须是整数
& 按位与
对应二进制位有0则0,全1为1
#includeint main(){int a = 3;// 0000 0000 0000 0000 0000 0000 0000 0011原码// 0000 0000 0000 0000 0000 0000 0000 0011补码int b = -5;// 1000 0000 0000 0000 0000 0000 0000 0101原码// 1111 1111 1111 1111 1111 1111 1111 1011补码printf("%d\n", a & b); // 有0则0,全1为1// 0000 0000 0000 0000 0000 0000 0000 0011// 1111 1111 1111 1111 1111 1111 1111 1011// 0000 0000 0000 0000 0000 0000 0000 0011 结果 3return 0;}
| 按位或
对应二进制位有1则1,全0为0
#includeint main(){int a = 3;// 0000 0000 0000 0000 0000 0000 0000 0011原码// 0000 0000 0000 0000 0000 0000 0000 0011补码int b = -5;// 1000 0000 0000 0000 0000 0000 0000 0101原码// 1111 1111 1111 1111 1111 1111 1111 1011补码printf("%d\n", a | b); // 有1则1,全0为0// 0000 0000 0000 0000 0000 0000 0000 0011 // 1111 1111 1111 1111 1111 1111 1111 1011 // 1111 1111 1111 1111 1111 1111 1111 1011 补码// 1000 0000 0000 0000 0000 0000 0000 0101 -5return 0;}
^ 按位异或
对应的二进制位不同为1,相同为0
#includeint main(){int a = 3;// 0000 0000 0000 0000 0000 0000 0000 0011原码// 0000 0000 0000 0000 0000 0000 0000 0011补码int b = -5;// 1000 0000 0000 0000 0000 0000 0000 0101原码// 1111 1111 1111 1111 1111 1111 1111 1011补码printf("%d\n", a ^ b); //不同为1,相同为0// 0000 0000 0000 0000 0000 0000 0000 0011 // 1111 1111 1111 1111 1111 1111 1111 1011 // 1111 1111 1111 1111 1111 1111 1111 1000 补码// 1000 0000 0000 0000 0000 0000 0000 1000 -8return 0;}
不使用中间变量,实现两个数的交换(按位异或)
#include int main(){int a = 3;int b = 5;/*常规做法int tmp = a;a = b; b = tmp;*///不允许使用中间变量/*a = a + b; //把和放到a中b = a - b; //b为和减去ba = a - b; //a为和减去b缺陷:a和b很大,二者的和会超过int的范围*/a = a ^ b;b = a ^ b;a = a ^ b;// a^a0// a^0a// a = 3;// b = 5;// a^b^a ?// a 0011// b 0101// a^b 0110// a^b^a 0110 0011—— 0101—— b// a^a^b a^a=0 0^b=b// a^b^a = a^a^b ,交换律printf("%d %d\n", a, b);return 0;}
赋值操作符
赋值操作符中除了**=**外,还有很多个复合赋值操作符, +=,-=,*=,/=,%=,>>=,<<=,&=,|=,^=
单目操作符
单目操作符的操作数只有一个
!逻辑取反
可以理解为把真的变成假的,把假的变成真的
#includeint main(){int x = 0;if (x == 0)printf("hello\n");if (!x)printf("world\n");if (x)printf("!\n");return 0;}
在上述代码中,有三个条件语句,第一个当x为0,输出hello;第二个0为假,非0为真,所以 !x为真,输出world;第三个0为假,非0为真,所以x为假,不输出 !
+ –
这里的 +, –,是正值和负值的意思,并不是加和减的意思,-1的负号就是单目操作符,它的操作数只有一个;2-1的减号是双目操作符,它的操作数有两个,分别是2和1。
& *
& 为取地址, * 不是乘的意思,它是间接访问操作符,也称作解引用操作符,两者通常应用于指针。
#includeint main() {int a = 1;int* pa = &a; //&a将a的地址取出来,放到pa变量中,类型是int **pa = 2; //间接访问操作符,通过pa中存放的地址找到指向的内容或者空间int b = *pa;return 0;}
sizeof
sizeof是操作符,不是函数。它可以求变量或者类型所占空间的大小,单位是字节。
#includeint main(){int a = 1;printf("%d\n", sizeof(int));printf("%d\n", sizeof(a));printf("%d\n", sizeof a);//printf("%d\n", sizeof int);错误写法return 0;}
除此之外,sizeof还可以计算数组的大小,单位同样是字节。
#includeint main(){int arr[10] = {0};printf("%d\n", sizeof(arr));printf("%d\n", sizeof(int [10])); //[]中的数字不能去掉//printf("%d\n", sizeof(int [])); 错误写法return 0;}
~ 按位取反
按位取反是对二进制进行取反。
#includeint main(){int a = 0;printf("%d\n", ~a);//0的补码是 0000 0000 0000 0000 0000 0000 0000 0000//对0的补码取反为1111 1111 1111 1111 1111 1111 1111 1111//取反后的原码为 1000 0000 0000 0000 0000 0000 0000 0001//所以结果是-1return 0;}
下面这段代码,问题分析都在注释中写出来了
#includeint main(){int a = 13;//方便起见,只写八位//13是 0000 1101//要得到 0001 1101真值为29//按位或是有1则1//可以将13与 0001 0000按位或//0001 0000是0000 0001左移4位得到,也就是将1左移4位,将a按位或0001 0000即可a |= (1 << 4);printf("%d\n", a);//通过0001 1101真值为29 //得到0000 1101真值为13//按位与是全1才1//将0001 1101 按位与 1110 1111,即对0001 0000按位取反,也就是将1左移4位,取反。按位与。a &= (~(1 << 4)); //不知道优先级的话可以都带上括号printf("%d\n", a);return 0;}
感兴趣可以琢磨琢磨下面的代码
#includeint main(){int a = 0;//第一种写法//while (scanf("%d", &a) == 1)//{//printf("%d\n", a);//}//第二种写法//while (scanf("%d", &a) != EOF)//{//printf("%d\n", a);//}//第三种写法while (~scanf("%d", &a)){printf("%d\n", a);}return 0;}
++ 和 – –
++ 和 – – 分别都有前置和后置两种,前置为先运算后使用,后置为先使用后运算
关系操作符
> >= < <= != ==
注意:== 和 =的区别
逻辑操作符
&& 逻辑与(并且)|| 逻辑或(或者)
条件操作符
语句1 " />2 : 语句3类似于if (语句1)语句2;else 语句3;
C语言中唯一的三目操作符
逗号表达式
语句1,语句2,语句3,语句n从左向右计算,整个表达式的结果是最后一个表达式的值
下标引用、函数调用和结构成员
1.下标引用操作符 []操作数:数组名 + 索引值2.函数调用操作符 ()第一个操作数是函数名,剩余操作数是传递给函数的参数。最少有一个操作数3.访问结构成员 .结构体.成员名-> 结构体指针->成员名
#include struct Stu{char name[10];int age;char sex[5];double score;};void set_age1(struct Stu stu){stu.age = 18;};void set_age2(struct Stu* pStu){pStu->age = 18;//结构成员访问}int main(){struct Stu stu;struct Stu* pStu = &stu;//结构成员访问stu.age = 20;//结构成员访问set_age1(stu);pStu->age = 20;//结构成员访问set_age2(pStu);return 0;}