一、操作符与表达式
分类:算数操作符、移位操作符、位操作符、赋值操作符、单目操作符、关系操作符、逻辑操作符、条件操作符、逗号操作符、 下标引用、函数调用和结构成员。
1、算数操作符
+ - * / %
其中,%的两端必须为整数,返回的是整除后的余数;
/ 两边的3和5都是整数,除法执行的是整数除法,得到的结果是整数,如果想要得到小数,那么这样写
然而得到的结果是这个结果确不理想,所以如果想要得到正确的结果,/ 两端至少有一个数是浮点数,比如说
2、移位操作符
<< 左移操作符 >> 右移操作符
int main()
{
int a = 2;
int b = a << 1;//把a的二进制位向左移动一位
printf("b=%d\n", b);
return 0;
}
2是整数,放在a中,a又是整型变量,占了4个字节,也就是32个比特位,32个比特位放2是
,向左移动一位,就是把a的二进制序列拿起来,向左移动一位
左边的0丢弃,右边少一位则补0,
此时1在的三位,这是整个数字变成了4,放在b中,这是的b就是4
我们可以得出一个结论:左移操作符规则是左边丢弃,右边补0.
那向右移动呢?
int main()
{
int a = 10;
int b = a >> 1;//把a的二进制位向右移动一位
printf("b=%d\n", b);
return 0;
}
10的二进制序列
这时把它拿起来右移一位后把右边超出部分舍弃,那么左边要怎么补呢?首先我们要知道,内存中存了二进制序列,最高位时0则代表这个数是正数,最高位是1则这个数是负数.
右移分为两种,一种是算数右移,另一种是逻辑右移;
算数右移:右边丢弃,左补原符号位;
逻辑右移:右边丢弃,左边补0.
我们先运行上边的代码
一般来说,正数是看不出进行了什么右移,所以我们需要使用负数
int main()
{
int a = -1;
int b = a >> 1;//把a的二进制位向右移动一位
printf("b=%d\n", b);
return 0;
}
我们需要先知道,整数的二进制表示形式有3种,
1、原码:直接根据数值写出的二进制序列就是原码;
2、反码:原码的符号位不变,其他位按位取反就是反码;
3、补码:反码+1就是补码。
原、反、补码的算法是针对负数的,对于正整数,原、反、补码相同。
-1存放在内存中,存放的是二进制的补码
要把-1向右移动一位,就是把补码向右移动一位
如果是算术右移就在左边补0,如果是逻辑右移就补1
最终运行的结果是-1,所以当前的右移操作符使用的是算术右移。
可以看出,a的结果没有发生变化。
3、位操作符
& 按位与
| 按位或
^ 按位异或
注:它们的操作数必须是整数
int main()
{
int a = 3;
int b = 5;
int c = a & b;//&-按(2进制)位与
printf("%d\n", c);
return 0;
}
//对应的二进制位按位与————对应的二进制位只要有0按位与的结果就是0,对应的二进制位两个都是1按位与的结果才是1。
a:00000000000000000000000000000011——3
b:00000000000000000000000000000101——5
c:00000000000000000000000000000001——1
最终结果
int main()
{
int a = 3;
int b = 5;
int c = a | b;//|-按(2进制)位或
printf("%d\n", c);
return 0;
}
//对应的二进制位有真为真,两个为0则为0.
a:00000000000000000000000000000011——3
b:00000000000000000000000000000101——5
c:00000000000000000000000000000111——7
最终结果
int main()
{
int a = 3;
int b = 5;
int c = a ^ b;//^——按(2进制)位异或
printf("%d\n", c);
return 0;
}
//对应的二进制位相同为0,相异为1
a:00000000000000000000000000000011——3
b:00000000000000000000000000000101——5
c:00000000000000000000000000000110——6
最终结果
那么,位操作有什么用途呢?
先看这一道题:不创建变量,两个数字交换,即a=3,b=5变成a=5,b=3.
法1、
int main()
{
int a = 3;
int b = 5;
a = a + b;
b = a - b;
a = a - b;
printf("a=%d b=%d", a,b);
return 0;
}
//但是,这个写法有缺陷,数值太大会溢出
法2、
int main()
{
int a = 3;
int b = 5;
printf("a=%d b=%d\n", a,b);
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("a=%d b=%d\n", a, b);
return 0;
}
a^a=0——任何两个相同数字^为0
0^a=a——0和任何数异或还是它本身
a^b^b=a 可以看成先b^b,此时得到的是0;a^0的结果就是a。
int main()
{
int a = 13;
a = a | (1 << 4);
printf("a=%d\n",a);
return 0;
}
00000000000000000000000000001101——13
如果想把它变成00000000000000000000000000011101
则需要令00000000000000000000000000001101按位或00000000000000000000000000010000
00000000000000000000000000010000由1<<4产生的
4、赋值操作符
=
+= -= *= /= %= >>= <<= &= |= ^=这些是复合操作符
int main()
{
int a = 10;
a = 100;
a = a+100;
a += 100;//和上一种写法是等价的
a = a >> 3;
a >> =3;
return 0;
}
注意:=是赋值;==是判断相等
5、单目操作符——只有一个操作数
!——逻辑反操作
int main()
{
int flag = 5;
//flag为真,打印hehe
if (flag)
{
printf("hehe"\n);
}
//flag为假,打印haha
if (!flag)
{
printf("haha"\n);
}
return 0;
}
sizeof
int main()
{
int a = 10;
char arr[10] = {0};
printf("%d\n",sizeof(arr));//一个字符一个字节,10个就10个字节
int arr[10] = {0};
printf("%d\n",sizeof(arr));//一个字符4个字节,10个就40个字节
printf("%d\n",sizeof(int [10]));//int [10]就是arr的类型
printf("%d\n",sizeof(a));//计算a所占空间的大小,单位是字节
printf("%d\n",sizeof(int));//(int)的括号不能省
printf("%d\n",sizeof a );//证明了sizeof是操作符而不是函数,若为函数括号不能省
return 0;
}
sizeof
int main()
{
short s = 5;
int a = 10;
printf("%d\n",sizeof(s = a + 2));
printf("%d\n",s)
return 0;
}
打印结果:
2
5
//s = a + 2求出的结果是12放入s中,但sizeof计算的是s所占空间的大小,s是提前就开辟好的,所以表达式的结果由s说的算,所以算的结果为2
注:sizeof括号中放的表达式是不参与运算的。
~按位取反
int main()
{
int a = -1;
//100000000000000000000000000000001——原码
//111111111111111111111111111111110——反码
//111111111111111111111111111111111——补码
int b = ~a;
//111111111111111111111111111111111——补码
//000000000000000000000000000000000
printf("%d\n",b);
return 0;
}
练习:
int main()
{
int a = 13;
//把a的二进制为的第5位制成1
a = a | (1 << 4);
printf("a=%d\n",a);
a = a &~ (1<<4);
printf("a=%d\n",a);
//把a的二进制为的第5位制成0
00000000000000000000000000011101
按位与11111111111111111111111111101111
11111111111111111111111111101111由000000000000000000000000000010000按位取反得到
return 0;
}
后置++
int main()
{
int a = 10;
int b = a++;//后置++,先使用,再++
printf("%d\n",a);//11
printf("%d\n",b);//10
return 0;
}
前置++
int main()
{
int a = 10;
int b = ++a;//前置++,先++,再使用
printf("%d\n",a);//11
printf("%d\n",b);//11
return 0;
}
int main()
{
int a = 10;
printf("%d\n",a--);//10
printf("%d\n",a);//9
return 0;
}