操作符详解
分类:
算术操作符
移位操作符
位操作符
赋值操作符
单目操作符
关系操作符
逻辑操作符
条件操作符
逗号表达式
下标引用、函数调用和结构成员
算数操作符
+-*/%
#include<stdio.h>intmain(){//int a = 6 / 5;//printf("%d\n", a);//1//float a = 6 / 5;//printf("%f\n", a);//1.00000float a=6.0/5;printf("%f\n", a);//1.2return0;}
6/5算的结果就是商–1,所以把a改为float也没用,只能将6/5改为6.0/5或6/5.0或者6.0/5.0。
intmain(){int a=7%3;printf("%d\n", a);//1return0;}
1.除了%外,其他都能对整形或者浮点数进行运算
2.对于/操作符如果两个操作数都为整数,则执行整数除法,只要里面有浮点数则进行的是浮点数除法
3.%操作符的两操作数必须为整数,返回的是余数
求一个整数存储在内存中的二进制中1的个数
移位操作符
<< 左移操作符>> 右移操作符
左移操作符:
左边抛弃、右边补0
intmain(){int a=2;//把a的二进制位向左移动一位,最左边丢弃,右边加0//00000000000000000000000000000010//00000000000000000000000000000100---4int b= a<<1;printf("%d\n", b);//4return0;}
右移操作符:
首先右移运算分两种:
- 逻辑移位 左边用0填充,右边丢弃
- 算术移位 左边用原该值的符号位填充,右边丢弃
intmain(){int a=10;//把a的二进制数向右移动一位//00000000000000000000000000001010//1.逻辑移位 左边用0填充,右边丢弃//00000000000000000000000000000101---5//2.算术移位 左边用符号位填充,右边丢弃//00000000000000000000000000000101---5int b= a>>1;printf("%d\n", b);//5return0;}
负数可以测试出是算术移位还是逻辑移位
intmain(){int a=-1;//把a的二进制数向右移动一位//11111111111111111111111111111111//逻辑右移//01111111111111111111111111111111//00000000000000000000000000000001----1 原码//算术右移//11111111111111111111111111111111//10000000000000000000000000000001----- -1 原码int b= a>>1;printf("%d\n", b);//-1 可以看出用的是算术右移return0;}
可以看出采用的是算术右移。
注意:对于移位运算符,不要移动负数位,这个是标准未定义的。
位操作符
&//按位与|//按位或^//按位异或
注:他们的操作数必须是整数。
按位与
intmain(){int a=3;int b=5;//& - 按(二进制)位与int c= a& b;//00000000000000000000000000000011//00000000000000000000000000000101//00000000000000000000000000000001 -- 1printf("%d\n", c);return0;}
按位或
intmain(){int a=3;int b=5;//& - 按(二进制)位与int c= a| b;//00000000000000000000000000000011--a//00000000000000000000000000000101--b//每一位进行或//00000000000000000000000000000111 -- 7printf("%d\n", c);return0;}
按位异或
intmain(){int a=3;int b=5;//& - 按(二进制)位与int c= a^ b;//00000000000000000000000000000011--a//00000000000000000000000000000101--b//每一位进行异或--相同为0,不同为1//00000000000000000000000000000110 --6printf("%d\n", c);//6return0;}
一道面试题:
不借助临时变量将两个变量的值交换
intmain(){int a=3;int b=5;printf("a=%d b=%d",a,b);
a=a^b;//a^b^b=a a^b^a=b
b=a^b;
a=a^b;return0;}
求一个整数存储在内存中的二进制中1的个数
//int a=7;//00000000000000000000000000000110//123//123%10 得到3//123/10=12 去掉3// %10 /10
intcount_one(int n){int count=0;while(n)//n如果不是0,二进制序列一定有1{if(n%2==1){
count++;}
n=n/2;}return count;}intmain(){int a=6;int ret=count_one(a);printf("%d\n",ret);return0;}
这个代码有问题的,如果a=-1时,编译的1的个数为0,
intcount_one(int n){int count=0;int i=0;for(i=0;i<32;i++){if(((n>>i)&1)==1){
count++;}}return count;}intmain(){int a=-1;//原码:10000000000000000000000001//反码:11111111111111111111111110//补码:11111111111111111111111111//内存中存的是补码//让这个数字和1按位与//11111111111111111111111111111111//00000000000000000000000000000001//00000000000000000000000000000001//最后一位为1得到1,最后一位为0得到0int ret=count_one(a);printf("%d\n",ret);return0;}
上面的代码一定会循环32次,下面这个代码更高效
//n=n&(n-1)//每一次都让二进制序列中最右边的1消失//在n变成0之前,让n=n&(n-1),这个操作执行一次count++//n=7//111-n//110//110-n//101//100-n//011//000-nintcount_one(int n){int count=0;while(n){
n=n&(n-1);
count++;}return count;}intmain(){int a=-1;int ret=count_one(a);printf("%d\n",ret);return0;}
赋值操作符
intmain(){int a=0;
a=3;//赋值操作符//与==容易混淆,判断是否相等}
赋值操作符可以连续赋值,但是不建议
intmain(){int a=10;int x=0;int y=20;
a=x=y+1;return0;}
复合赋值符
intmain(){int a=0;
a=a+3;
a+=3;//简单明了
a=a-10;
a-=10;
a=a>>1;
a>>=1;
a=a&1;
a&=1;}
单目操作符
intmain(){3+5;//+ 有两个操作数 双目操作符//单目操作符-只有一个操作数的操作符return0;}
!逻辑反操作
intmain(){int a=10;//10-非零-真printf("%d\n",!a);//0//把真变成假,假变成真int flag=1;if(!flag)//flag为假时进来{}}
-负值操作符
intmain(){int a=-10;
a=-a;
a=+a;//正号可以省略}
&取地址操作符
intmain(){int a=10;//4个字节空间int* pa=&a;//拿到了a的地址,指针变量printf("%p\n",&a);//&-取地址操作符return0;}
*解引用操作符
intmain(){int a=10;//4个字节空间int* pa=&a;//拿到了a的地址,指针变量*pa=20;//*解引用操作符,拿到areturn0;}
sizeof操作符
操作数的类型长度(单位是字节)
intmain(){int a=10;int arr[10]={0};printf("%d\n",sizeof(arr));//计算数组的总大小printf("%d\n",sizeof(int[10]));printf("%d\n",sizeof(a));//4printf("%d\n",sizeof(int));//4return0;}
intmain(){short s=5;int a=10;printf("%d\n",sizeof(s= a+2));//2 这里没有参与运算,没有整形提升printf("%d\n", s);//5return0;}
sizeof括号中放的表达式是不参与运算的!
a+2的结果不一定会放入s里面,但是如果放进去,这个表达式的类型s说了算。
#include<stdio.h>voidtest1(int arr[]){printf("%d\n",sizeof(arr));//(2)}voidtest2(char ch[]){printf("%d\n",sizeof(ch));//(4)}intmain(){int arr[10]={0};char ch[10]={0};printf("%d\n",sizeof(arr));//(1)printf("%d\n",sizeof(ch));//(3)test1(arr);test2(ch);return0;}
问:
(1)、(2)两个地方分别输出多少?
(3)、(4)两个地方分别输出多少?
我们将数组名进行传参时,传过去的是首元素的地址,地址得用指针来接收,其实函数参数本质上是个指针,大小是4(32位)或者8(64位)。
~操作符
对一个二进制位按位取反
intmain(){int a=0;printf("%d\n",~a);//00000000000000000000000000000000//按位取反//11111111111111111111111111111111补码//%d打印的是原码//11111111111111111111111111111110反码//10000000000000000000000000000001原码//-1return0;}
intmain(){int a=14;
a|=(1<<4);printf("%d\n",a);
a&=(~(1<<4));printf("%d\n",a);//00000000000000000000000000001110 将第五位变为1//00000000000000000000000000010000//按位或//00000000000000000000000000011110 将第五位再变回0//11111111111111111111111111101111//按位与则将第五位变回0,其他位不变return0;}
++ --操作符
intmain(){//a++是表达式int a=10;//a++表达式先使用a的值,a再++int b=a++;//后置++ //先使用a,再++printf("a=%d b=%d\n",a,b);//11 10int b=++a;//前置++ 先++,后使用aprintf("a=%d b=%d\n",a,b);//11 11return0;int a=10;int b=a--;//后置-- //先使用a,再--printf("a=%d b=%d\n",a,b);//int a=10;int b=--a;//前置-- //先--,再使用aprintf("a=%d b=%d\n",a,b);//int a=10;printf("%d\n",a++);}
intmain(){int a=1;int b=(++a)+(++a)+(++a)printf("%d\n",b);return0;}
错误代码,vs环境编译为12,Linux环境编译为10。
(类型)强制类型转换
intmain(){int a=3.14;printf("%d\n",a);return0;}
会出现警告,不想出现警告,可以这样做
intmain(){int a=(int)3.14;printf("%d\n",a);return0;}
关系操作符
>>=<<=!===
在编程中小心==和=不小心写错导致错误
一些关系不能用关系操作符比较的:
例如字符串的比较
逻辑操作符
&&逻辑与
||逻辑或
逻辑与和逻辑或只看真假
intmain(){int a=3;int b=5;//a&b;//按二进制位与//a&&b;//逻辑与int c=a&&b;//a,b都为真,c才为真printf("%d\n",c);return0;}
intmain(){int a=0;int b=5;int c=a||b;//只要有一个真则为真printf("%d\n",c);return0;}
intmain(){int i=0,a=0,b=2,c=3,d=4;
i= a++&&++b&& d++;printf("a=%d b=%d c=%d d=%d",a,b,c,d);//1 2 3 4return0;}
注意:对于&&操作符,左边如果为零,编译器就不会计算右边了
对于||操作符,左边如果为1,右边就不计算了
条件操作符
三目操作符-三个操作数
表达式1?表达式2:表达式3
表达式1为真,算的是表达式2的结果,否则为表达式3的值
intmain(){int a=10;int b=20;int max=0;
max=a>b?a:b;return0;}
逗号表达式
逗号表达式,就是用逗号隔开的多个表达式。逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
int a=1;int b=2;int c=(a>b,a=b+10,a,b=a+1);//逗号表达式
下标引用、函数调用、和结构成员
下标引用
intmain(){int arr[10]={1,2,3,4,5,6,7,8,9,10};//arr+4printf