前言
小伙伴们大家好,随着对c的不断学习今天我们将来学习操作符。在初始c语言中也介绍过操作符但也只是点到即可,今天我们将详细了解操作符。
操作符分类:
算术操作符
移位操作符
位操作符
赋值操作符
单目操作符
关系操作符
逻辑操作符
条件操作符
逗号表达式
下表引用,函数调用和结构成员
算术操作符
算术操作符都有哪些呢?让我们一起来看看吧。算术操作符包括:+ - * / %.在数学中乘号是X,但是在c语言中乘号是用*来表示的。同样的还有除号,也与数学中的写法不一样。同时还要注意的两个点,第一当除号两端都是整数时执行的是整数除法结果也是整数;除号有一端是小数时执行小数除法,所得的结果也是小数的形式。


第二个值得注意的点就是%,%是取模也被称之为取余。%的两端只能是整数不能是小数

当%的两端有一端是小数时,编译器会报错并提示有小数的一端非法

位移操作符
操作符移动的是二进制位,此时不得不先提整数的二进制表示形式。以int a = -3为例,int 是4个字节一个字节是八个比特位,所以此时a的二进制位有32位10000000000000000000000000000000011。整数的二进制表示形式有三种:原码,反码,补码。还是以a为例,此时a的原码为10000000000000000000000000000000011。反码:最高位不变,其余位进行按位取反,此时a的反码为11111111111111111111111111111100,。补码:在反码的基础上进行加1,此时a的补码为11111111111111111111111111111101.需要注意的是,正整数的原码反码补码都是一样的,而负整数的原码反码补码需要进行计算得出。可能有小伙伴要问了为啥我们非得要补码呢?原码不可以直接用吗?我们要求补码,是因为整数在内存中的存储是以补码的形式。
左移操作符<<
左移操作符移的是二进制的是二进制位

a的二进制位是000000000000000000000000000000011,把a的二进制位向左移一格,舍弃左边,右边补0,此时我们会得到b的二进制位000000000000000000000000000000110,b的值为6.上代码

简单归纳,左移操作符的使用方法是舍弃左边,右边补0.
右移操作符>>
左移操作符移的是二进制位,同样右移操作符移的也是二进制位。不过右移操作符分为两种:一种是逻辑右移,另一种是算术右移。逻辑右移:右边丢弃,左边直接用0填充。算术右移:右边丢弃,左边原来的符号位填充。在代码中是使用算术右移还是逻辑右移,这是由编译器决定的。不过一般都是使用算术右移。

从这里可以看出实现的是算术右移。那我们来分析一下倘若进行逻辑右移时又会有什么不同呢?让我们一起来看看吧。a=-3,其二进制位原码为10000000000000000000000000000011,反码:最高位不变,其余位进行按位取反得到11111111111111111111111111111100,补码:在反码的基础上加一得到11111111111111111111111111111101。当a按照算术右移来移动已为时,右边丢弃左边直接补0得到补码为:01111111111111111111111111111110 。补码减一取反得到原码:00000000000000000000000000000010此时得到a>>1的值为2.
不管是左移操作符还是右移操作符移动的都是整数,一定不能是小数。同时移动整数时一般移动的都是正整数。直接上代码来看看效果吧。当a左移的是一个负数时编译器会发出警告,同时运行结果是一个负数


这里我们需要注意,位移操作符移动的是整数且是正整数
位操作符
位操作符的分类:按位与&,按位或|,按位异或^。不管是按位与还是按位或还是按位异或中的位都是二进制位
按位与&
按位与简单来说就是,有0则0.用代码来理解吧

按位或|
按位或简单来说:有1则为1.依旧是用代码来理解吧

按位异或^
按位异或的使用方法:相同为0相异为1.依旧是用代码理解

来利用按位异或的知识来写一道题吧。题目要求为不使用临时变量来交换两个变量的值。
在之前的学习中交换两个变量的值我们会通过使用临时变量。但这题的要求是不使用临时变量。第一种解决方法
#include<stdio.h>
int main()
{
int a = 3;
int b = 5;
printf("a=%d b=%d\n", a, b);
a = a + b;//a=8
b = a - b;//b=8-3=5;
a = a - b;//a=8-5=3;
printf("a=%d b=%d\n", a, b);
return 0;
}

此时达到了交换变量值的目的,但是这种代码存在问题。当a和b的值非常大时,a+b的结果容易溢出。这种方法还是不太好。
第二种方法利用按位异或来进行解决
#include<stdio.h>
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的二进制位00000000000000000000000000000011
b的二进制位00000000000000000000000000000101
第一次按位异或得到a的值,这个值作为交换变量值的桥梁
a^b的结果为:00000000000000000000000000000110,a=a^b,此时a的值为6
再进行按位异或得到b的值
b=a^b::00000000000000000000000000000011 ,b的值为3
最后进行一次按位异或得到a的值
a=a^b:00000000000000000000000000000101,a的值为5.
赋值操作符
赋值操作符=,这里要注意区别与==。=是赋值操作符,==是判断相等。赋值操作符可以改变变量之前的值
double salary = 10000.0;
salary = 20000.0//使用赋值操作符进行赋值
int weight = 110;
weight = 90;//对体重不满意就可以赋值
复合赋值
+= : a= a+b;可以改成a+=b;
-= : a=a-b可以改成a -= b;
/=: a=a/b可以改为a/=b
%=: a=a%b可以改为a%=b;
>>=: a=a>>1改为a>>=1
<<+: a=a<<=1改为a<<=1
&= : a=a&b改为a&=b;
|= : a=a|b改为a|=b;
^=: a=a^b改为a^=b;
单目操作符
单目操作符的分类
!逻辑反操作符,++自增操作符,--自减操作符,&取地址操作符,*解引用操作符,~对一个二进制位进行按位取反,+正值,-负值,sizeof操作数类型大小(单位为字节),(类型)强制类型转化
!逻辑反操作符
!逻辑反操作符,例如a=1为真是,那么!a为假。倘若b=0时为假,那么!b为真
++自增操作符
++自增操作符分为前置++和后置++。前置++先加加再使用;后置加加,先使用再加加。直接上代码来康康它们的区别吧
int main()
{
int a = 10;
int b = a++;
printf("a=%d,b=%d ", a, b);//a=11,b=10
return 0;
}

int main()
{
int a = 10;
int b = ++a;
printf("a=%d,b=%d ", a, b);//a=11,b=11
return 0;
}

--自减操作符
--自减操作符也分为前置--和后置--.前置减减先减减再使用;后置减减,先使用再减减。上代码
int main()
{
int a = 10;
int b = --a;
printf("a=%d,b=%d ", a, b);//a=9,b=9
return 0;
}

int main()
{
int a = 10;
int b = a--;
printf("a=%d,b=%d ", a, b);//b=10,a=9
return 0;
}

&取地址操作符
&取地址操作符可以取出变量或者数组的地址,然后把地址放在指针变量中存储起来。
int main()
{
int a = 10;
int * pa = &a;
printf("%p ", pa);
return 0;
}
此时可以通过pa找到a的地址

int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9 };
printf("%p ", &arr);
return 0;
}

*解引用操作符
解引用操作符通常和取地址操作符搭配使用
int main()
{
int a = 10;
int* pa = &a;
*pa = 20;
printf("%d ", a);
return 0;
}

把a的地址放在指针变量pa中,再通过解引用操作符对pa进行解引用操作。*pa就相当于是a
~对二进制位进行按位取反
直接上代码来康康吧
int main()
{
int a = -3;//原码:10000000000000000000000000000011;
//反码:11111111111111111111111111111100
//补码:11111111111111111111111111111101
a = ~a; //~a;000000000000000000000000000000010
printf("%d ", a);
return 0;
}
sizeof操作数类型的大小
sizeof用来计算所占空间大小单位为字节,不但可以计算变量的大小还可以计算数组大小。让我们一起来看看代码吧
int main()
{
int a = 10;
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(int));
int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(int[10]));
return 0;
}

(类型)强制类型转化操作符

这种出现了一个警告,从double转化到int 可能丢失数据。此时有两种解决办法:第一种将int a 改为double a.把a的类型改为浮点型。第二种方法在10.0/3之前放一个(int)将结果转化为整形


以上就是操作符详解的上篇,欲知下事如何请听下回分解。操作符详解下篇正在准备中。
创作不易还望各位大佬们点赞,么么哒
