大家好!今天我们说一下C语言中的操作符知识,主要有两个方面:1. 各种操作符的介绍 2. 表达式求值,操作符的种类还是比较多的但是不必担心我会一一讲解。这篇文章我先说第一块内容,下一篇文章讲第二部分。好了,话不多说,直接开始。
算术操作符就4个,加,减,乘,除,取余(模)。我们主要介绍后面两个:
1. 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。
我们可以看到10/3不是小数,而是整数3。我们给int改成double也没用。
我们要得到正确的小数,必须两个操作数其中至少一个是浮点数。
2. % 操作符的两个操作数必须为整数。返回的是整除之后的余数。
我们可以看到这样写是错误的。
除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。
1.<< 左移操作符
2.>> 右移操作符
注:移位操作符的操作数只能是整数。这里的位指的是内存中存储的二进制位。
在这我要补充一点知识:什么是二进制?
我们正常数学中用到的是十进制,有0~9个数,逢十进一,而二进制只有0和1,逢二进一。
我们举个例子:
假设a=5,a是整型,a占4个字节->32个bit,a转换成2进制是:
00000000000000000000000000000101-原码
00000000000000000000000000000101-反码
00000000000000000000000000000101-补码
这里最高位表示的是符号位,0代表正数,1代表负数。
假设a=-5,转换成2进制为:
10000000000000000000000000000101-原码
反码是:符号位不变,其余取反
11111111111111111111111111111010-反码
补码是:反码+1
11111111111111111111111111111011-补码
小结:
重点:整数在内存中存储的是补码。
懂得了这些知识,我们举些例子:
移位规则:左边抛弃、右边补0
#include
int main()
{
int a = -5;
int b = a << 2;
printf("%d\n", b);
printf("%d\n", a);
return 0;
}
-5的补码是:11111111111111111111111111111011
向左移动两位,在最后面补两个0。
新的补码:11111111111111111111111111101100
虽然在内存中存储都是用补码的,但在打印或者使用的时候,用的是原码的值。
所以,我们要倒推回去,补码-1得到反码:11111111111111111111111111101011
符号位不变,其余取反得到原码:10000000000000000000000000010100
转换成10进制是:-20
所以b的值是-20,那么a的值呢?是变为-20呢?还是没有变化呢?
我们看一下运行结果:
我们可以看到a的值没有发生变化,这里的运算不改变a,例如:b=a+1,a还是原来的值,发生变化的是b。
移位规则:
首先右移运算分两种:
1.逻辑移位
左边用0填充,右边丢弃
2.算术移位
左边用原该值的符号位填充,右边丢弃
到底是算术还是逻辑,取决于编译器,常见的编译器都是算术右移
我们看一下这个例子:
int main()
{
int a = -5;
int b = a >> 1;
printf("%d\n", b);
return 0;
}
首先,-5的补码:11111111111111111111111111111011
然后右移一位,我们先假设是算术位移,左边补1:11111111111111111111111111111101
反码=补码-1:11111111111111111111111111111100
原码:100000000000000000000000000000011
转化为10进制:-3
我们来看一下运行结果:
所以在vs2019下,是算术右移。
警告⚠ :
对于移位运算符,不要移动负数位,这个是标准未定义的。
例如:
int num = 10;
num>>-1;//error
这是错误的。
位操作符有:
这些位也都是二进制位,也都是按照补码计算。我们举些例子看下:
讲解一下:正数的原码,反码,补码是一样的。
3的补码是:00000000000000000000000000000011
-5的补码是:11111111111111111111111111111011
按位与的意思是:对应的位只要有一个0就为0
c的补码是:00000000000000000000000000000011
打印时要是原码,我们可以看到最高位为0,是正数,所以原,反,补相同。
c的值为:3
如果改成按位或呢?按位或:对应的二进制位只要有一个1就为1
3的补码是:00000000000000000000000000000011
-5的补码是:11111111111111111111111111111011
结果应该是:11111111111111111111111111111011
反码:11111111111111111111111111111010
原码:10000000000000000000000000000101
结果是:-5
按位异或的意思是:对应的二进制位相同的为0,不同的为1方法和上面一样,这里就不举例了。
我们来看一道笔试题:
不能创建临时变量(第三个变量),实现两个整数的交换。
我们想一下:a^a=0. a^0=a.
假设a=a^b, 然后再a^b 的意思就是a ^ b ^ b,我们知道 b ^ b=0,所以0 ^ a就为a。然后我们将它赋值给b
这样我们就把a的值放到b里面了。然后,我们再a ^ b,这个意思就相当于是a ^ b ^ a。因为a是a ^ b,b是原来a的值。所以,就为结果为b,放到a里面。
这样就交换了。
赋值操作符是一个很棒的操作符,它可以让你得到一个你之前不满意的值。也就是你可以给自己重新赋值。
直接看代码:
int weight = 120;//体重
weight = 89;//不满意就赋值
double salary = 10000.0;
salary = 20000.0;//使用赋值操作符赋值
赋值操作符可以连续使用,比如:
int a = 10;
int x = 0;
int y = 20;
a = x = y+1;//连续赋值
这样的代码感觉怎么样?同样的语义:
x = y+1;
a = x;
这样的写法是不是更加清晰爽朗而且易于调试。
复合赋值符
这些运算符都可以写成复合的效果。比如:
int x = 10;
x = x+10;
x += 10;//复合赋值
其他运算符一样的道理。这样写更加简洁。
什么叫做单目操作符:就是只有一个操作数的。
第一个:逻辑反操作符,就是让真变为假,假变为真。
第五个:可以求变量(类型)所占空间的大小,举个例子:
在这要记住一点,sizeof不是函数。看代码:
sizeof 后面的括号去掉依旧可以使用,所以也说明了这个问题。
第六个,按(内存中补码的二进制位)位取反。
其余的我在《初识C语言》那篇文章说过,不懂的可以去看看那个。
这些关系运算符比较简单,没什么可讲的,但是我们要注意一些运算符使用时候的陷阱。
警告:
在编程的过程中== 和=不小心写错,导致的错误。
区分逻辑与和按位与。
区分逻辑或和按位或。
逻辑操作符只关心真与假,和二进制位没关系。
我们来看一道笔试题:
这道题结果是什么?我们可以思考一下:
运行结果如下:
为什么是这个结果?我们知道a++是后置++,所以先使用a,a为0,所以第一个表达式为假,为假则后面的++b的表达式就没有计算,a++ && ++b为假,所以d++也没有计算,所以就第一个表达式执行了,然后a++就为1。
我们再看一下这个结果:a++是后置++,a是1为真,++b就没有计算,所以a++ || ++b就为真,所以d++就没有计算,所以就第一个表达式执行了,然后a++就为2,结果为:2 2 3 4
小结:
&& 左操作数为假,右边不计算。
|| 左操作数为真,右边不计算。
也叫三目操作符
这个意思就是表达式1是否为真。为真则表达式2成立,为假表达式3成立。
逗号表达式,就是用逗号隔开的多个表达式。
逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
1.[ ] 下标引用操作符
操作数:一个数组名 + 一个索引值
2.( ) 函数调用操作符
接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数。
3.访问一个结构的成员
举个例子:
操作数第一部分讲完,这些就是C语言所有的操作数。下一篇文章我会讲解表达式求值,它的内容也是有许多要注意的地方,好了,如果大家认为我有哪些不足之处或者知识上的错误都可以告诉我,我会在之后的文章中不断改正,也请大家多多包涵。如果大家觉得这篇文章有用的话,也希望大家可以给我关注点赞,你们的支持就是对我最大的鼓励,我们下一篇文章再见。