这一篇主要讲一下操作符的相关知识。
1.算数操作符。
算数操作符一共为五个:+, -, *, /, %, 加减乘没什么可说的,主要是后面两个有需要注意的点。除号需要注意的地方在于,若想要计算的某个值有小数的话,直接使用float库函数是不行的,必须得保证除号操作符两边至少有一个小数。
而对于%取余符号来说,其两边的操作数都必须为整数,不能浮点型操作数进行去余。
2.位移操作符。
首先明确一点,这里所谓的位移,移动的是二进制位。
其次,整数的二进制位其实是有三种形式的,分别是:源码,反码和补码。其中对一个数进行打印,其打印的就是源码,也就是这个数的二进制序列。反码就是在源码基础上,把0改为1,把1改为0。而补码则是在反码的基础上加一,而进行位移操作的对象就是补码。当然以上这些都是针对负整数,如果是正整数,三码相同。
先来说左移动操作符,以代码举例:
可以看到整数5进行左移得到的是整数10。
因为:
整数5的二进制最后八位为:00000101 其他位都为0。而左移操作符的规则是左边抛弃后边补0,那么位移以后的后八位就是:00001010,转换为十进制,就是整数10。
而假设是整数-5,进行左移动:
与正整数5不同的地方在于,负整数的补码需要进行计算:
源码为1.........00000101 注意二进制数第一位为符号位,若为0则是正数,若为1则是负数
反码就在源码基础上进行反补,但是注意符号位除外:1..............11111010.
反码加一就为补码:1...........11111011
然后就在这个补码的基础上左移补0,就为1............11110110.
最后这个补码一路返回,最后得到的就是符号位为1的整数10的源码。
再来说右移操作符。
右移操作符有两种位移规则:逻辑位移,右移一位,左端用0补齐。算数位移,右移一位。左端用符号位填充。至于是用哪种位移规则,则是由编译器决定。
还是以代码举例:
方法与左移是一样的,先算出补码,再位移。然后再返回源码得出结果。
3.位操作符。
位操作符共有三种:& 按位与; | 按位或; ^按位异或。这三种操作符对应的也是操作二进制位
按位与,是当两个操作数二进制数对应位数都为一时,改为1。
按位或,当两个操作数二进制数对应位数只要有1 就改为1 ,都为0才改为0。
按位异或,两个操作数二进制数对应位如果相同则为0,不同则为1。
注意这三个操作符的操作数必须为整数,用代码演示就可以得到如下结果:
扩展一点,在不创建临时变量的前提下,怎么交换两个数的值?这里也可以用到位操作符:
这里的第二个等式中,可以理解为b = a ^ b ^ b, 在这里要注意任何数与其本身按位异或,都等于0 ,而0与任何整数按位异或都为其本身,所以可以得到b = a,同样的道理第三个表达式也可以得到 a = b,因此就能实现数的交换。
4.赋值操作符。
即一个等号。注意与双等号区分。尤其是在条件判断的语句中要特别注意是双等号还是单等号。当然也有一些复合的赋值操作符。 如a = a + 1 就可以写为a += 1。同样的减等,或等都是如此。
5.单目操作符。
如!反逻辑操作符, &取地址操作符这些。但有些操作符也有着需要注意的点。
sizeof是操作符,而不是函数。这点要特别注意。再来看一个代码:
从这个代码中,能得出结论:sizeof括号中的表达式是不参与计算的。所以最后的打印s仍然为0,。其次,s是char类型只有两个字符,而a + 2是整形,这样会产生溢出,只有二个字节的大小。因此打印出来为2.。
再看一个代码:
这个代码要注意的地方在于,函数所传过去的只是一个地址,一个指针。无论数组是什么类型,指针都是整形的,因此大小应该是一样的。
6.关系操作符。
这个操作符相对于就比较简单。主要注意单个等号与双等号的使用。
7.逻辑操作符&& ||
注意连续的&& 和 ||,连续的并操作符,若最左边的为假,后面的就不会进行执行了。而对于连续的或则反之。
8.条件操作符exp1 ? exp2 : exp3
若exp1,判定为真,这执行exp2,反之则执行exp3。在执行这个操作符的时候,切勿嵌套,为了复杂而复杂。
9.逗号表达式。
用逗号隔开的多个表达式,从左向右执行,整个表达式的结果是最后一个表达式的结果。但是要注意前面的表达式如果有最后一个表达式的参数,是会影响最后一个表达式的输出的。
10.结构成员操作符。
用于对结构体的成员进行指出:
11.隐式类型转换
首先要知道,C语言整形算数运算总是以整型精度来进行的。而有时候所运算的对象可能不一定能达到整型,因此要先将其转换为整型,在进行运算,这被称为整型提升。以代码举例:
在这个代码中可以看到,由于a b 都为char类型,不满足整型的需求。因此得进行整型提升,提升后再加最后再转为char类型,大概如图所示:
再来说一下,操作符的相关属性。共三个,分别是操作符的优先级,操作符的结合性以及是否控制求值顺序。在这里有一个最基本的规则是优先级大的先执行,若优先级相同,由结合性决定先操作谁。具体可以参考优先级表。
遗留问题:递归与迭代的差异?
--------------------------------------------最后编辑于2023.3.2晚上八点五十左右