一、算术操作符
算术操作符包括:加号(+),减号(-),乘号(*),除号(/),取模(%)。
大家都非常了解这些操作符,但是有一些注意的地方需要说明一下。
除号(/)
1/5打印结果是0.这里就要说一下为什么结果是0,而不是0.2呢?
1/5,除号两边的两个操作符是整数,所以这里进行的是整数除法,1/5就是商0余1.
如果换成6/5打印结果就是1,这里就是商1余1.这就是整数除法。
那么我们如何改正了?
想要打印出浮点数,除号两端的操作数最少要有一个是操作符,这样执行的就是浮点数的除法。
取模(%)
取模(%)操作符的两个操作数必须是整数。
返回的是整除之后的余数。
二、移位操作符
(<<)左移操作符
(>>)右移操作符
左移操作符
右移操作符
右移操作符分为两种:
算术右移,右边丢弃,左边补原符号位。
逻辑右移,右边丢弃,左边补0。
a的二进制序列:
00000000 00000000 00000000 00000010
向右移动一位:
00000000 00000000 00000000 00000001
由于a是正数,所以不管是逻辑运算,还是算术运算,左边都是补0,所以得到的b的值就是1。
如果是负数呢?那又会有咋样的变化呢?
负数:-1
说到这里必须交代一个知识点,
整数的二进制的表示形式有三种,分别是原码,反码,补码。
原码:直接根据数据写出的二进制序列就是原码。
反码:原码的符号位不变,其他位按位取反就是反码。
补码:反码+1,就是补码。
-1的二进制序列:
原码:10000000 00000000 00000000 00000001
反码:111111111 111111111 111111111 111111110
补码:111111111 111111111 111111111 111111111
现在我们把-1向右移动一位,如果你当前的编译器采用的是算术右移,右边丢弃,左边补原符号位。
如果是逻辑右移,右边丢弃,左边补0。
注:把a向右移动一位,a的值是不变的,我们只是把a向右移动一位的值放到b里面,a的值是不变的。
三、位操作符
(&)按位与
(|)按位或
(^)按位异或
按位与
#include<stdio.h>
int main()
{
int a = 3;
int b = 5;
//& ➡️ 按(2进制)位与
//a ➡️ 00000000 00000000 00000000 00000011
//b ➡️ 00000000 00000000 00000000 00000101
//对应的2进制位按位与,只要有0,结果就是0,两个都是1结果才为1
//按位与后的结果 ➡️ 00000000 00000000 00000000 00000001
int c = a & b;
printf("%d\n", c);//打印结果为1
return 0;
}
按位或
#include<stdio.h>
int main()
{
int a = 3;
int b = 5;
//| ➡️ 按(2进制)位或
//a ➡️ 00000000 00000000 00000000 00000011
//b ➡️ 00000000 00000000 00000000 00000101
//对应的2进制位按位或,只要有1,结果就是1,两个都是0结果才为0
//按位与后的结果 ➡️ 00000000 00000000 00000000 00000111
int c = a | b;
printf("%d\n", c);//打印结果为7
return 0;
}
按位异或
#include<stdio.h>
int main()
{
int a = 3;
int b = 5;
//^ ➡️ 按(2进制)位异或或
//a ➡️ 00000000 00000000 00000000 00000011
//b ➡️ 00000000 00000000 00000000 00000101
//对应的2进制位按位异或,相同为0,相异为1
//按位与后的结果 ➡️ 00000000 00000000 00000000 00000110
int c = a ^ b;
printf("%d\n", c);
return 0;
}
注:这三个操作符的操作数必须都是整数。
四、赋值操作符
(=)赋值操作符(+= -= *= /= %= <<= >>= &= |= ^=)复合赋值操作符
赋值操作符
一个等号(=)叫做赋值,两个等号(==)叫做判断
#include<stdio.h>
int main()
{
int a = 0;
int b = 1;
if (a == b)
{
printf("hehe\n");
}
else
{
printf("haha\n");
}
return 0;
}
注:字符串比较是不可以使用==来比较
复合操作符
#include<stdio.h>
int main()
{
int a = 10;
a += 10;
printf("%d", a);
return 0;
}
五、单目操作符
! 逻辑反操作
- 负值
+ 正值
sizeof 操作数的类型长度(以字节为单位)
~ 对一个数的二进制按位取反
- - 前置 后置 - -
++ 前置 后置 ++
!逻辑反操作符
#include<stdio.h>
int main()
{
int a = 5;
if (a)
{
//a为真时打印hehe
printf("hehe\n");
}
if (!a)
{
//a为假时打印haha
printf("haha\n");
}
return 0;
}
负值与正值
#include<stdio.h>
int main()
{
int a = 2;
a = -a;
printf("%d\n", a);//打印-2
return 0;
}
#include<stdio.h>
int main()
{
int a = 2;
a = +a;
printf("%d\n", a);//打印2
return 0;
}
a = +a这种写法可以忽略,没什么用。
sizeof 操作数的类型长度
计算一个类型或者变量所占内存的大小。
#include<stdio.h>
int main()
{
int a = 5;
printf("%d\n", sizeof(a));//打印4
printf("%d\n", sizeof(int));//打印4
return 0;
}
a的类型是int,sizeof(a)可以计算a所占空间的大小,单位是字节.
sizeof是一个操作符,不是函数.
打印的结果是2和5,为什么呢?
a+2虽然是一个int类型的值,但是c不会因为放了这样一个值空间就变大,而sizeof求的是c所占空间字节的大小,所以第一个打印的是2.
为什么第二个是5呢?因为sizeof内部存放的表达式是不会参与运算的,所以c的值不变。
~ 对一个数的二进制按位取反
#include<stdio.h>
int main()
{
int a = -1;
int b = ~a;
//~对一个数的二进制位按位取反
//-1的补码11111111 11111111 11111111 11111111
//b的值为00000000 00000000 00000000 00000000
printf("%d\n",b);//打印0
return 0;
}
- -前置、后置- -
++前置、后置++
#include<stdio.h>
int main()
{
int a = 10;
printf("%d\n", ++a);//打印11
printf("%d\n", a++);//打印11
return 0;
}
#include<stdio.h>
int main()
{
int a = 10;
printf("%d\n", --a);//打印9
printf("%d\n", a--);//打印9
return 0;
}
++前置,先++,后使用。
后置++,先使用,后++。
- -前置、后置- -同理。
六、关系操作
(>) 大于操作符
(>=) 大于等于操作符
(<) 小于操作符
(!=) 用于测试”不等于“
(==) 用于测试”等于“
关系表达式通常返回0或1,表示真伪。c语言中,0表示伪,所有非零值表示真。比如,99 > 1返回1,1 > 99返回0。注意,相等运算符==与赋值运算符=是两个不一样的运算符,不要混淆。
七、逻辑操作符
&& 逻辑与
|| 逻辑或
逻辑运算符还有一个特点,它总是先对左侧的表达式求值,再对右边的表达式求值,这个顺序是保证的。如果左边的表达式满足逻辑运算符的条件,就不再对右边的表达式求值。这种情况称为“短路”。
因为a++是后置++,所以先使用,后++,a为0,根据短路效应,&&前面的值如果为假后面的表达式就不进行计算了,所以最终的结果为1,2,3,4。
这次我们把a的值改为1,因为a为真,根据短路效应,|| 前面的值如果为真后面的表达式就不进行计算了,所以最终的结果为2,3,3,5。
八、条件操作符
exp1 ? exp2 : exp3
条件操作符也叫三目操作符
九、逗号表达式
逗号表达式,从左向右依次计算,整个表达式的结果是最后一个表达式的结果。
所以说c = 5,a = a + 3结果是5,b=a-4结果是3,c+=6结果是11.不能只算最后一个表达式的结果,一定要从左向右一次进行计算。