【C语言】——详解操作符
- 一、 操作符的分类
- 二、 算数操作符
- 2.1、 ++ + 、−- − 和 ∗* ∗
- 2.2、 // / 操作符
- 2.3、 % 操作符
- 三、 位移操作符
- 3.1、 原码、 反码、 补码
- (1)原码
- (2)反码
- (3)补码
- 3.2、 左移操作符 <<
- 3.3、 右移操作符 >>
- 四、 位操作符
- 五、 赋值操作符
- 5.1、 == = 操作符
- 5.2、 复合赋值操作符
- 六、 单目操作符
- 6.1、 ++ 与 — —
- (1)前置++
- (2)后置++
- (3) — —
- 6.2、 + 和 —
- 6.3、 强制类型转换
- 6.4、sizeof
- 6.5、!
一、 操作符的分类
- 算数操作符:
+ 、 - 、* 、/ 、%
- 位移操作符:
<>
- 位操作符:
& 、 | 、^ 、 ~
- 赋值操作符:
= 、 += 、 -= 、 *= 、 /= 、 %= 、 <>= 、 &= 、 |= 、 ^=
- 单目操作符:
! 、 ++ 、 -- 、 & 、 * 、 + 、 - 、 ~ 、 sizeof 、(类型)
- 关系操作符:
> 、 >= 、 < 、 <= 、 == 、!=
- 逻辑操作符:
&& 、 ||、!
- 条件操作符:
? 、:
- 逗号表达式:
,
- 下标引用:
[ ]
- 函数调用:
( )
- 结构成员访问:
. 、->
二、 算数操作符
+++、 −-− 、 ∗*∗ 、/ 、%
我们在写代码时,一定会涉及运算。
C语言中,为了方便运算,提供了算术操作符,他们都是双目操作符。
2.1、 +++ 、 −-− 和 ∗*∗
++ + 、 −- − 以及 ∗* ∗ 是用来完成加法、减法和乘法的.
他们都有两个操作数,位于操作符两端的就是他们的操作数。因此,这种操作符也叫做双目操作符。
代码示例:
#includeint main(){int a = 3, b = 5;int add = a + b;int sub = a - b;int mul = a * b;printf("%d + %d =%d\n", a, b, add);printf("%d - %d = %d\n", a, b, sub);printf("%d * %d = %d\n", a, b, mul);return 0;}
运行结果:
2.2、 /// 操作符
说到C语言中的除法运算,我想先给大家看个例子:
#includeint main(){int a = 5;int b = 2;float c = a / b;printf("%d / %d = %f\n", a, b, c);return 0;}
代码的运行结果是什么?会得到 2.52.52.5 吗?让我们一起来看看运行结果:
为什么会这样呢?明明存放结果的变量类型已经是浮点型 ( f l o a t )(float)(float) 了呀,为什么小数部分还是 000 呢?
原因在于C语言中的整数除法是整除,只会返回整数部分,丢弃小数部分
.
如果希望得到浮点数的结果,两个运算符必须至少有一个浮点数
,这时 C 语言就会进行浮点数除法.
参考代码:
#includeint main(){int a = 5;float b = 2;int c = a / b;printf("%d / %f = %d\n", a, b, c);return 0;}
运行结果:
哈哈哈,没想到吧!只有除数或被除数是浮点型 ( f l o a t )(float)(float) 也是不行的哦,结果也是要浮点型
( f l o a t )(float)(float)
参考代码:
#includeint main(){int a = 5;float b = 2;float c = a / b;printf("%d / %f = %f\n", a, b, c);return 0;}
运行结果:
2.3、 % 操作符
操作符 % 表示求模运算,即返回两个整数相除的余值。这个操作符只能用于整数,不能用于浮点数
。
同时,负数求模的规则是:结果的正负号由第一个运算数的正负号决定
参考代码:
#includeint main(){printf("%d\n", 11 % 5);printf("%d\n", 11 % -5);printf("%d\n", -11 % 5);printf("%d\n", -11 % -5);return 0;}
运行结果:
三、 位移操作符
左移操作符 : < <<<<<
右移操作符 : > >>>>>
注:位移操作符的操作数只能是整数。
3.1、 原码、 反码、 补码
位移操作符实质上是对数据的二进制位进行操作
,因此了解整数的二进制表示方法至关重要。
整数的二进制表示方法三种:
- 原码
- 反码
- 补码
对于(signed)int(signed )int (signed)int (有符号整型),它的三种表示方法均分为符号位
和数值位
两个部分。二进制序列中,最高位被当做符号位,剩余的都是数值位
。
符号位都是用 00 0 表示正,用 11 1 表示负。
正整数的原、 反、 补码都相同
负整数的三种表示方法各不相同
(1)原码
直接将数值按照正负数的形式翻译成二进制得到的就是原码。
示例一:
#includeint main(){int a = -10;return 0;}
- -10是存放在 aaa 中, aaa 是整型变量,有4个字节,即32个bit位
- 10的二进制为:1010
- -10为负数,负数用最高位 1 来表示
- 因为一共4个字节,中间位用 0 补为位
(2)反码
将原码的符号位不变,其他位依次按位去反,即反码
(3)补码
反码 +1 就得到补码
示例二:
#includeint main(){int a = 10;return 0;}
而对于正数来说,它的三种表示方法相同:
补码得到原码:
- −1-1 −1 ,取反
- 取反,+1+1 +1
对于整型来说:数据存放内存中都是用补码进行运算和存储
原因在于,使用补码,可以将符号位和数值位统一处理;同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码和原码相互转换,其运算过程是相同的(取反,+1+1 +1),不需要额外的硬件电路。
3.2、 左移操作符 <<
移位规则:左边抛弃、右边补 0
注:调试时,在需要观测的整型变量后面加上 “ , b,b,b ”,即为其二进制表示。
运行结果:
图示:
3.3、 右移操作符 >>
移位规则:首先右移运算分为两种:
- 逻辑右移:左边用 000 填充,右边丢弃
- 算术右移:左边用原该值的符号位填充,右边丢弃
注:大部分编译器都是算术右移。
运行结果:
图示:
注:对于移位操作符,不要移动负数位,这个标准是未定义的!
int a = 10;a >> -1//error
四、 位操作符
位操作符有:
& 按位与
| 按位或
^ 按位异或
~ 按位取反
注:他们的操作数必须是整数,且操作的都是二进制位
(1)& 按位与
逻辑:有 0 为 0,全 1 为 1
运行结果:
图示:
(2)| 按位或
逻辑:有 1 为 1,全 0 为 0
运行结果:
图示:
(3)^ 按位异或
逻辑:相同为 0,相异为 1
运行结果:
图示:
(3)~ 按位取反
运算结果:
五、 赋值操作符
= 、 += 、 -= 、 *= 、 /= 、 %= 、 <>= 、 &= 、 |= 、 ^=
5.1、 === 操作符
在创建变量的时候给一个值初始值叫初始化,在变量创建好后,再给一个值,这叫赋值。
int a = 0;//初始化a = 200;//赋值,这里使用的就是赋值操作符
赋值操作符 == = 是一个随时可以给变量赋值的操作符。
赋值操作符也可以连续赋值
,如:
int a = 3;int b = 5;int c = 0;c = b = a + 5;//连续赋值,从右向左依次赋值
注:C语言虽然支持这种连续赋值,但是写出的代码不易理解,建议还是拆开来写
,这样方便观测代码的执行细节。
5.2、 复合赋值操作符
在写代码时,我们可能经常对一个数自增、自减的操作:
int a = 10;a = a + 3;a = a - 2;
这样代码C语言提供了更加方便的方法:
int a = 10;a += 3;a -= 2;
C语言中提供了复合赋值符,方便我们编写代码,这些附值符有:
+= 、 -= 、 *= 、 /= 、 %= 、 <>= 、 &= 、 |= 、 ^=
六、 单目操作符
! 、 ++ 、 -- 、 & 、 * 、 + 、 - 、 ~ 、 sizeof 、(类型)
在C语言中,有些操作符只有一个操作数,他们被称为单目操作符。
6.1、 ++ 与 – –
++是一种自增操作符,分为前置++和后置++,– –是一种自减操作符,也分为前置– –和后置 – –
(1)前置++
#includeint main(){int a = 10;int b = ++a;printf("%d %d\n", a, b);return 0;}
运行结果:
这段代码中,aa a 原来是 10 ,先 +1 , aaa 变为11,再使用就是赋值给 bbb ,bb b 得到的也是11,所以 aa a 和 bb b 都是 11。
计算口诀:
先 +1,后使用
相当于以下代码:
#includeint main(){int a = 10;a = a + 1;int b = a;printf("%d %d\n", a, b);return 0;}
(2)后置++
#includeint main(){int a = 10;int b = a++;printf("%d %d\n", a, b);return 0;}
运行结果:
上述代码中, aa a 原来是10,先使用,就是先赋值给 bbb , bb b 得到了10,然后 aaa 自增成了11,所以运行结果 aa a 是11,bb b 是10.
计算口诀:
先使用,后 +1
相当于如下代码:
#includeint main(){int a = 10;int b = a;a = a + 1; printf("%d %d\n", a, b);return 0;}
(3) – –
– – 操作符和 ++ 原理一样,只是自增变成自减而已,这里就不再过多赘述了,下面给段代码大家一起来检验一下吧
#includeint main(){int a = 10;int b = a--;int c = --a;printf("%d %d %d\n", a, b, c);return 0;}
运行结果:
怎么样,你做对了吗?
6.2、 + 和 –
这里的 + 是正号, – 是负号,他们都是单目操作符。
操作符 + 对正负值没有影响,是一个完全可以省略的操作符,但是写了也不会报错
#includeint main(){int a = 10;int b = +10;printf("%d %d\n", a, b);return 0;}
操作符 – 用来改变一个正值的正负号,在负数的前面加上 – 就会得到正数,在正数前面加上 – 就会得到负数。
#includeint main(){int a = 10;int b = -a;int c = -10;printf("b = %d c = %d\n", b, c);int aa = -10;int bb = -aa;printf("bb = %d\n", bb);return 0;}
6.3、 强制类型转换
在操作符中还有一种特殊的操作符是强制类型转换,语法形式很简单,如下:
(类型)
请看代码:
#includeint main(){int a = 3.14;printf("%d/n", a);return 0;}
为了消除这个警告,我们可以使用强制类型转换:
#includeint main(){int a = (int)3.14;printf("%d\n", a);return 0;}
但,俗话说:强扭的瓜不甜,我们使用强制类型转换都是万不得已的时候使用
,如果不需要强制类型转换就能实现代码,这样自然最好。
6.4、sizeof
看到这,是不是很惊讶呢,没错!sizeofsizeof sizeof 并不是函数,而是一个操作符
sizeofsizeof sizeof 是一个关键字,也是一个操作符,是专门用来计算类型长度的,单位是字节
s i z e o fsizeofsizeof 是单目操作符,操作数可以是类型
,也可以是变量
或者表达式
。
sizeof(类型)sizeof 表达式
- s i z e o fsizeofsizeof 的操作数如果不是类型,是表达式的时候,可以省略后边的括号的。
- s i z e o fsizeofsizeof 后边的表达式是不真实参与运算的,根据表达式的类型雷得出大小。
- s i z e o fsizeofsizeof 的计算结果是 s i z esizesize_ ttt 类型的。
sizeofsizeof sizeof 操作符的返回值,C语言只规定是无符号整数,并没有规定具体类型,而是留给系统自己决定。sizeofsizeof sizeof 到底返回什么类型,在不同的系统中,返回值的类型有可能是 unsignedunsigned unsigned intint int ,也有可能是 unsignedunsigned unsigned longlong long,甚至是 unsignedunsigned unsigned longlong long longlong long。他们对应的 printf()printf() printf() 占位符分别是 %uu u、%lulu lu和 %llullu llu。这样不利于程序的可移植性。
C语言提供了一个解决方法,创造了一个类型别名 sizesize size_tt t,用来统一表示 sizeofsizeof sizeof 的返回值类型。对应当前系统的 sizeofsizeof sizeof 的返回值类型,可能是unsignedunsigned unsigned intint int ,也可能是unsignedunsigned unsigned longlong long longlong long。
比如:
#includeint main(){int a = 10;printf("%zd\n", sizeof(a));printf("%zd\n", sizeof a);//a是变量的名字,可以省略sizeof后面的()printf("%zd\n", sizeof(int));printf("%zd\n", sizeof(3 + 3.5));return 0;}
sizeofsizeof sizeof中表达式不计算 !
#includeint main(){short s = 2;int b = 10;printf("%d\n", sizeof(s = b + 1));printf("s = %d\n", s);return 0;}
s i z e o fsizeofsizeof 在进行编译的时候,就根据表达式的类型确定了,而表达式的执行却要在程序运行期间才能执行,在编译期间已经将 sizeofsizeof sizeof 处理掉了,所以在运行期间就不会再执行表达式了。
6.5、!
在C语言中:0 为假,非 0 为真(负数也为真)
! 操作符作用是:逻辑取反
图示:
比如,我们有一个变量 flagflag flag,如果 flagflag flag 为假,要做一个什么事情,就可以这样写代码:
#includeint main(){int flag = 0;if (!flag){printf("do something\n");}return 0;}
如果 flagflag flag 为真,!flag!flag !flag 就是假,如果 flagflag flag 为假, !flag!flag !flag 就是真
所以上面的代码意思是 flagflag flag 为假,执行 i fifif 语句中的代码.
剩下的两个单目操作符 & 和 ∗*∗,将在之后指针内容一起介绍,敬请期待!