写在前面:这篇博文为c语言中所有操作符的介绍以及使用它们时要注意的一些点。博主水平有限,文章若有错误之处,望读者斧正。
文章目录
操作符分类
首先我们要知道c语言的操作符可以分成十大类
- 算术操作符
- 移位操作符
- 位操作符
- 赋值操作符
- 单目操作符
- 关系操作符
- 逻辑操作符
- 条件操作符
- 逗号表达式
- 下标引用,函数调用和结构成员操作符
下面开始一个个介绍它们
1.算术操作符
+ - * / %
我们可以用数学中的运算符来理解c语言中的算术操作符,前面三个操作符就没什么好介绍的。对于 / 操作符,只要除号两边的操作数存在浮点数,就执行浮点数除法运算,算出的结果为浮点数;两个操作数都为整数,就进行整数除法运算。
虽然a和b作为两个浮点型变量,能存储浮点数,但在5/2这个表达式中,除号的两个操作数为整形,执行整数除法运算,结果为5/2的商。在表达式5.0/2中,一个操作数为浮点数,执行浮点数除法运算,得到的值就是精确的2.5。
接着是%(取模操作符),取模运算得到的结果是两数相除的余数。
有一个地方要注意,取模操作符的两个操作数必须为整数。
但除了取模操作符之外,其他的操作符都能用作于整数或者浮点数。
2.移位操作符
移位操作符有两个
>> 左移操作符
<< 右移操作符
在学习移位操作符之前,我们先要了解整数在计算机中的储存形式。
2.1原码,反码和补码
数据在计算机中都是以补码的形式存储的,提到补码就不得不说原码与反码。
原码就是把一个十进制数翻译成二进制序列。符号位不变(符号位为二进制序列的首位),对原码按位取反(把1变成0,0变成1)得到反码,对反码加一得到补码。正数的原码,反码,补码相同。举个例子,把5翻译成二进制序列是多少呢?
5为整形,整形有4个字节,就是32个比特位,32个二进制位,上面的图片就是计算机眼中的5。由于正数的原码,反码,补码相同,不用对5的二进制序列进行转化,5的补码就是原码。
那-5的二进制序列呢?
和5的二进制序列一样,只是把符号位改为1,这表示它是一个负数,而这只是-5的原码,由于-5是负数,我们需要对它进行转化,才能得到-5的补码。除了符号位,对其他位按位取反得到反码。
再对反码加一得到补码。
-5的三种二进制存储形式。
最终-5以补码的形式存储在内存中,但是我们在打印-5时,又要把-5的补码转化成原码。这个原理暂时不说,其实我不会 因为有点复杂,展开了就偏离这次的主题了。
2.1移位操作符介绍
移位操作符针对的是整数,要移动的位数必须是正整数。
对移动的方向进行分类,我们把移位操作符分为左移操作符和右移操作符。先来说说左移操作符,把10左移一位,这个移动操作是怎么实现的?用图片演示左移的过程
可以看到,10的二进制位向左移动一位,右边空出一位,空位补0,左边舍弃一位。现在表示的数是20,因此,我们能把左移一位理解为乘以2。
与左移不同,右移操作分为逻辑右移与算术右移,具体的移动形式由编译器决定。何为逻辑右移?二进制位向右移动一位,左边的空位补0。算术右移,空位补原来的符号位。什么意思呢?
上图表示的是-5逻辑右移,无论数字的正负,空位补0,那-5的算术右移呢?
空位补充的数字由原来数字的符号位决定,原来是负数,空位补1,是正数,空位补0
最后,不要对一个数移动负数位,比如
int num = 5;
num >> -1;
这是什么意思,右移-1位?直接说左移1位不行吗吗?这种代码编译器不能识别出来,我们尽量不要写这种奇怪的代码(正常人谁这样写代码啊),平时要注意,别一不小心写成这样的错误代码了。
3.位操作符
位操作符有三种
& //按位与
| //按位或
^ //按位异或
它们的操作数必须是整数。
3.1按位与
这里的位指的是二进制位,两个数都为1,按位与的结果是1,一个数为0,按位与的结果都是0。举个例子,
根据0与任何数按位与都等于0,两个数都为1按位与结果为1的原则,结合画图理解,我们就能很好的理解按位与。
3.2 按位或
而按位或也是大同小异,1与任何数按位或都等于1。两个数都为0,按位或结果才为0。这里就不画图了,还是比较简单的。
3.3 按位异或
按位异或的运算原则是:两数相同为0,不同为1。有一个有趣的规律,两个相同的数异或,结果是0;某个数与0异或,结果为本身(结果不变)。运用异或的知识,我们可以在不创建第三个变量的情况下,实现两个数的交换,
4. 赋值操作符
= += -= *= /= %= >>= <<= &= |= ^=
顾名思义,我们能运用赋值操作符把值赋给变量。在变量初始化的时候我们能用它来赋初值,之后也能用它来对变量重新赋值
我们不满意60的分数,就对分数重新赋值,现在的分数就变为100了
注意点:不要搞混了= 与 == 这两个操作符,=在c语言中是赋值,两个=是用来判断两个操作数是否相等。
4.1 复合赋值符
当我们要写a = a + 10 时,可以用更简洁的写法,这时就要运用复合赋值符 += ,把表达式写成a += 10。其他的复合赋值符也类似,这里不再一一列举。
5. 单目操作符
! 逻辑反操作
- 负值
+ 正值
& 取地址
sizeof 操作数的类型长度(以字节为单位)
~ 对一个数的二进制按位取反
-- 前置、后置--
++ 前置、后置++
* 间接访问操作符(解引用操作符)
(类型) 强制类型转换
有的操作符在之前已经介绍过了,这里就挑几个重点的讲讲
5.1 !逻辑反操作
我们知道,在计算机中,0表示假,非0表示真。对一个非0的数逻辑反操作得到的是0,0则是假。对0逻辑反操作得到的是1(计算机中的!0始终表示1),1表示真。这就是逻辑反操作的用法。
5.2 前置与后置++
前置++,操作数先自增,再使用。后置++,先使用操作数,再自增。举个例子
–与++的实现是相似的,这里不再赘述。
5.3 按位取反
对补码的每个二进制位取反(1变成0,0变成1)
6. 关系操作符
>
>=
<
<=
!= 用于测试“不相等”
== 用于测试“相等”
用来判断两个操作数是否相等,注意赋值符=与判断相等符号==的区别
7. 逻辑操作符
&& //逻辑与
|| //逻辑或
可以用数学里的并且和或者来理解这两个操作符。表示一个数大于0并且小于18时,在数学里是用0 < x < 18表示的,但c语言不这样表示,我们要写成
x > 0 && x < 18
一定不能写成数学里的形式。
7.1 逻辑短路
在由&&和||组成的表达式中,逻辑短路是经常发生的,那逻辑短路又是什么呢?
在a++ && b-- && c++这个表达式中,程序按照从左向右的顺序计算,由于a是后置++,先使用后自增,但a的值为0,一个表达式的结果为0,整个表达式的结果就为0,这是逻辑与的特点,所以a++后面的表达式没有必要算下去,程序对a自增后,直接跳过b–与c++,所以从结果中我们看到b与c的值都没变。
逻辑或呢?把刚刚代码里的逻辑与改成逻辑或,看程序是怎么运行的,a先使用再自增,a为0结果为假,程序继续运行,b–,先使用b,b为1,为真,b自增后程序不再运行(逻辑或中,程序执行的表达式为真,整个表达式就为真,程序没有再运算的必要,所以直接跳出,c的值没有加一。
由于程序直接跳出,我们给这种动作起了个形象的名字:逻辑短路。一些程序阅读题会经常考查这个知识点,在平时做题时要注意逻辑的短路。
8. 条件表达式
条件表达式又叫三目表达式
exp1 ? exp2 : exp3
如果exp1成立,程序执行exp2,若不成立,程序执行exp3。这个表达式我经常用来判断两个数的最大值。
int main()
{
int a = 10;
int b = 20;
max = a > b ? a : b;
}
9. 逗号表达式
(exp1,exp2,exp3...expn)
用逗号把表达式隔开(养成好习惯,逗号表达式一定要加上括号),程序会从左向右运算每一个表达式,逗号表达式的结果是最后一个表达式的结果。不过我们不能直接计算最后一个表达式,因为之前的表达式可能影响最后一个表达式的值。
int a = 1;
int b = 2;
int c = (a++, b++, a + b);
能直接说c的值是3吗?显然,直接计算最后一个式子是错误的,程序要从左向右计算,因此程序先自增a,然后自增b,最后结果是5。
10. 下标引用,结构成员和函数调用
下标引用操作符是[ ],当我们创建数组,想访问数组成员时,就要用到它
更详细的讲解我在数组那篇博文说过了,有兴趣的欢迎访问浅谈数组。
函数调用操作符我也说过,再不要脸的贴个链接函数基础知识点讲解。
这里主要讲解下结构成员操作符
. 操作符,左边是结构体变量名,右边是结构体的成员,打印a.name我们就能知道a的书名。用指正变量时,我们也能访问结构体成员,只要对指针变量解引用就行。不对指针变量解引用,我们也可以用->操作符,左边是结构体变量,右边是结构体内容,pa->name表示的是pa指针指向的name。
最后:这篇文章内容太多,整理的时候好几次想放弃(因为自己对这块知识还是比较熟悉的),最后还是肝出来了,并且修改了好多次。如果这篇文章有帮助到你,看在博主这么用心的份上,hxd点个赞再走呗。