操作符详解
点击此处可以查看一些简单的题目[操作符详解题目演示:?https://blog.youkuaiyun.com/wang_yiduo/article/details/87089064)
算术操作符
+ - * / %
注意 1:除了%之外,其余的几个操作符可以用于整数和浮点数.
注意2:%是求余的操作,连个操作数必须为整数,返回的值是整除之后的余数
移位操作符
<<左移操作符
>>右移操作符
左移操作符移位规则:左边抛弃,右边补0(左移一位相当于乘以2)
如:(32位操作系统下)
a=2
二进制为:00000000000000000000000000000010
a<<1
二进制为:00000000000000000000000000000100
此时a=4
补充:负数的二进制:负数的二进制为其绝对值的补码取反再加1
a=1
二进制为:00000000000000000000000000000001
补码: 00000000000000000000000000000001
取反(~): 11111111111111111111111111111110
加1: 11111111111111111111111111111111
a=-1
二进制为: 11111111111111111111111111111111
右移操作符移位规则:
-
逻辑移位:左边用0填充,右边丢弃
-
算数移位:左边用原该值符号位填充,右边丢弃
a=-1 二进制为: 11111111111111111111111111111111 a>>1(算术右移):11111111111111111111111111111111 a>>1(逻辑右移):01111111111111111111111111111111(错误的移位)
注意1:负数只能算数右移,正数既能算术右移也能逻辑右移,所以右移尽量都采用算术右移
注意2:移位操作符不能移负数位如:a>>-1或者a<<-1,是错误的
位操作符
& //按位与:同为1才为1,其余都为0
| //按位或:同为0才为0,其余都为1
^ //按位异或:相同为0,不同为1
~ //按位取反:0变1,1变0
代码演示:
#include<stdio.h>
int main()
{
int a=1;
int b=2;
int x1=a&b;
//a二进制为:00000000000000000000000000000001
//b二进制为:00000000000000000000000000000010
//a&b= 00000000000000000000000000000000
int x2=a|b;
//a|b= 00000000000000000000000000000011
int x3=a^b;
//a^b= 00000000000000000000000000000011
int x4=~a;
//~a=11111111111111111111111111111110
printf("x1=%d,x2=%d,x3=%d,x4=%d\n",x1,x2,x3,x4);
return 0;
}
结果为:x1=0,x2=3,x3=3,x4=-2
这里之所以x4=-2是因为x4是按照有符号十进制打印的,如果按照无符号打印那x4将接近于整形能够表达的最大的数,在42亿9千万左右,牵扯到了数据的存储问题,可以看我的数据在内存中的存储那一章博客.
赋值操作符
= //可以重新赋值,以最新赋的值为准
注意:赋值操作符"=“和”==“是不同的,”=“是将等号右边的值赋给左边的值,而”=="是关系操作符用以判断相等不相等
代码演示:
#include<stdio.h>
int main()
{
int a=1;
int b=2;
b=a;
a=3;
printf("a=%d,b=%d\n",a,b);
return 0;
}
结果为:a=3,b=1
原因:a最后一次赋的值为3,所以a=3,b虽然赋的值为a,但是再给b赋值的时候,a那时为1,所以b=1,即便a后来变为3,但是并不影响b
复合赋值符
+= *= /= %= >>= <<= &= |= ^=
注意:a+=1指的是a=a+1后面的也都是同一个模式
单目操作符
sizeof //操作数的类型长度(以字节为单位)
(类型) //强制类型转换
! //逻辑反操作值为真变假,值为假变真
- //负值
+ //正值
& //取地址
* //间接访问操作符(解引用操作符)
~ //对一个数的二进制按位取反
-- //前置,后置减1
++ //前置,后置加1
演示代码:
#include<stdio.h>
int main()
{
int a=-10;
int* p=NULL;
a=-a;
p=&a;
printf("!2=%d",!2);
printf("!0=%d",!0);
printf("sizeof(int)=%d",sizeof(int));
printf("sizeof(a)=%d",sizeof(a));
printf("*p=%d\n", *p);
printf("&a=%p\n", &a);
}
结果:!2=0,!0=1,sizeof(int)=4,sizeof(a)=4,*p=10,&a是存的10的地址
原因:2为真,逻辑反为假,假为0,0为假,逻辑反为真,真用1来表示
前置++,- -和后置++,- -
- 前置++和前置–是先对操作数进行自增或者自减,然后使用
- 后置++和后置–是先对操作数进行使用,然后自增或者自减
代码演示:
#include<stdio.h>
int main()
{
int a=1;
int b=++a;
printf("a=%d\n",a);
printf("b=%d\n",b);
int c=--a;
printf("a=%d\n",a);
printf("c=%d\n",c);
return 0;
}
结果为:a=2,b=2,a=1,b=1
原因:++a先自增,a=2,赋给b,所以b=2; --a先自减,a=1,赋给c,所以c=1;
#include<stdio.h>
int main()
{
int a=1;
int b=a++;
printf("a=%d\n",a);
printf("b=%d\n",b);
int c=a--;
printf("a=%d\n",a);
printf("c=%d\n",c);
return 0;
}
结果为:a=2,b=1,a=1,c=2;
原因:a++先对a使用,将a赋给b,所以b=1,在对a自增,a=2; a–先对a使用,将a赋给c,所以c=2,在对a自减,a=1
关系操作符
> < >= <= != ==
注意:这些关系操作符用以比较两个操作数之间的关系
逻辑操作符
&& //逻辑与:同真为真,其余为假
|| //逻辑或:同假为假其余为真
注意:要将逻辑或( || )和按位或( | )以及逻辑与( && )和按位与( & )区分开来
逻辑与和或的特点:会出现短路求值的情况
代码演示:
#include<stdio.h>
int main()
{
int a=0,b=2,c=3;
int x=a++&&++b&&c++;
printf("x=%d,a=%d,b=%d,c=%d\n",x,a,b,c);
a=0;b=2;c=3;
int y=a++||++b||c++;
printf("y=%d,a=%d,b=%d,c=%d\n",y,a,b,c);
return 0;
}
结果:x=0,a=1,b=2,c=3; y=1,a=1,b=3,c=3
原因:
- 再求x的时候,a++先对a使用,a=0为假,&&同为真才为真其余都为假,所以x为假,x=0,发生短路,不在计算b和c,a使用完后自增,所以a=1,b=2,c=3;
- 再求y的时候,a++先对a使用,a=0为假,||同为假才为假其余都为真,无特殊情况发生,a自增后,a=1;++b先自增,b=3,b非0为真,||同为假才为假其余都为真,所以y为真,y=1,发生短路,不在计算c,所以c=3;
条件运算符(三目运算符)
exp1?exp2:exp3
代码演示:
#include<stdio.h>
int main()
{
int a=1;
if(a>3)
a=5;
else
a=-5;
printf("a=%d\n",a);
}
//等价于
#include<stdio.h>
int main()
{
int a=1;
a>3?5:-5;
printf("a=%d\n",a);
}
逗号表达式
exp1,exp2,exp3,.......expn
逗号表达式作用:用逗号隔开多个表达式,从左至右依次执行,但是整个表达式的结果是最后一个表达式的结果
代码演示:
#include<stdio.h>
int main()
{
int a=1;
int b=2;
int c=(a>b,a=b+10,a,b=a+1);
printf("c=%d\n",c);
}
结果:c=13
原因:逗号表达式从左至右依次执行,a>b为假,a=b+10,a=12,b=a+1,b=12+1=13,因为整个表达式的结果是最后一个表达式的结果,所以c=13
表达式求值
-
隐式类型转换
(整形提升)在进行数学运算的时候,会将char和short类型的数据转换成为int,在进行计算
整形提升规则://高位补符号位(无符号高位补0) char a=1; 二进制为:00000001 整形提升:00000000000000000000000000000001 char b=-1; 二进制为:11111111 整形提升:11111111111111111111111111111111
代码演示:
#include<stdio.h> int main() { char a=1; char b=2; a=(~a^b<<1)>>1; //~a二进制: 11111111111111111111111111111110 //b的二进制: 00000000000000000000000000000010 //二者按位异或:11111111111111111111111111111100 printf("a=%d\n",a); }
结果:a=-3
原因:a进行取反操作首先a会变成int类型接着取反,此时为-1,在和b按位异或为-3,左移右移各一次等于没变,所以a=-3
算术转换
当不同类型的数据在进行运算时,低精度会转向高精度
代码演示:#include<stdio.h> int main() { float a=1.8; float b=a/2; int c=a/2; printf("b=%f\n",b); printf("c=%d\n",c); }
结果:b=0.900000;c=0
原因:c是int类型数据,只有4个字节,b是float类型数据,有8个字节,发生了精度丢失,int无法表示float的全部数据,所以在计算时要时刻小心这类问题转换表:
long double; double; float; unsigned long int; long int; unsigned int; int;
注意:如果某个操作数的类型在上面排名较低,那么首先要转成另外一个操作数的类型后再进行计算