运算符
运算符
苏丙榅熟悉了如何表示数据之后,接下来我们学习如何处理数据。C 语言为处理数据提供了大量的操作,可以在程序中进行算术运算、比较值的大小、修改变量、逻辑地组合关系等。下面先为大家数量一下C语言中常用的运算符分类:
运算符类型 | 作用 |
---|---|
算术运算符 |
用于处理四则运算 |
赋值运算符 |
用于将表达式的值赋给变量 |
比较运算符 |
用于表达式的比较,并返回一个真值或假值 |
逻辑运算符 |
用于根据表达式的值返回真值或假值 |
位运算符 |
用于处理数据的位运算 |
sizeof 运算符 |
用于求字节数长度 |
1. 算术运算符
下表中为大家列出了C语言中先关的算法运算符,其使用方法也很简单:
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
+ |
正号 | +3 | 3 |
- |
负号 | -3 | -3 |
+ |
加 | 10 + 5 | 15 |
- |
减 | 10 - 5 | 5 |
* |
乘 | 10 * 5 | 50 |
/ |
除 | 10 / 5 | 2 |
% |
取模(取余) | 10 % 3 | 1 |
++ |
前自增 | a=2; b=++a; | a=3; b=3; |
++ |
后自增 | a=2; b=a++; | a=3; b=2; |
-- |
前自减 | a=2; b=–a; | a=1; b=1; |
-- |
后自减 | a=2; b=a–; | a=1; b=2; |
关于正号(+
)、负号(-
)、加(+
)、减(-
)、乘(*
)、除(/
)运算符这里就不再过多赘述了,使用发方法和我们学习的数学知识是一致的。
- 取余(
%
):被除数和除数进行除法运算,舍弃商保留其余数。 - 前缀自增(
++
):运算符++
写到变量前面,先进行自增运算,然后取变量的值 - 后缀自增(
++
):运算符++
写到变量后面,先取变量的值,然后进行自增运算 - 前缀自减(
--
):运算符--
写到变量前面,先进行自增运算,然后取变量的值 - 后缀自减(
--
):运算符--
写到变量后面,先取变量的值,然后进行自减运算
1 |
|
程序输出的结果为:
1 | result1 = 6, i = 6 |
通过上面的例子可以得出以下结论:
- 对于变量自身来说,不论是
前自增/自减
还是后自增/自减
,最后变量的值都会增/减 1,这种情况下前/后自增、前/后自减是等价的 - 如果想要取出某个自增/自减变量的值:
- 后自增/自减是先取变量的值,然后变量再进行自增/自减运算
- 前自增/自减是变量先进行自增/自减运算,然后再取该变量的值。
2. 赋值运算符
赋值运算符(Assignment Operators)的作用就是将右侧的值赋给左侧的变量。在C语言中,常见的赋值运算符有以下几种:
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
= |
赋值 | a=2; b=3; | a=2; b=3; |
+= |
加等于 | a=0; a+=2;(a=a+2) | a=2; |
-= |
减等于 | a=5; a-=3;(a=a-3) | a=2; |
*= |
乘等于 | a=2; a*=2;(a=a*2) | a=4; |
/= |
除等于 | a=4; a/=2;(a=a/2) | a=2; |
%= |
模等于 | a=3; a%2;(a=a%2) | a=1; |
其他还有位运算赋值符(如:按位与等于&=
、按位或等于|=
、按位异或等于^=
)和移位运算赋值符(如:左移等于<<=
、右移等于>>=
)。这些运算符可以进行类似的操作,将左侧变量和右侧的值进行位运算或移位运算,并将结果赋给左侧变量。
这些赋值运算符可以简化代码,同时更新变量的值。
3. 比较运算符
比较运算符(Comparison Operators)用于比较两个值之间的关系,并返回一个布尔值(true
或false
)。在C语言中,常见的比较运算符有以下几种:
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
== | 相等于 | 4 == 3 | 0 |
!= | 不等于 | 4 != 3 | 1 |
< | 小于 | 4 < 3 | 0 |
> | 大于 | 4 > 3 | 1 |
<= | 小于等于 | 4 <= 3 | 0 |
>= | 大于等于 | 4 >= 1 | 1 |
这些比较运算符常用于条件语句(如if语句、循环语句等)中,根据表达式的结果来决定程序的执行逻辑(后续章节中会进行详细讲解)。
4. 逻辑运算符
逻辑运算符(Logical Operators)用于对多个条件进行逻辑运算,并返回一个布尔值(true或false)。在C语言中,常见的逻辑运算符有以下几种:
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
! |
非 | !a | 如果a为假,则!a为真;如果a为真,则!a为假。 |
&& |
与 | a && b | 如果a和b都为真,则结果为真,否则为假。 |
|| | 或 | a || b | 如果a和b有一个为真,则结果为真,二者都为假时,结果为假。 |
- 逻辑与(&&):当所有条件都为 true 时,返回 true,否则返回 false。
- 逻辑或(||):当至少一个条件为 true 时,返回 true,否则返回 false。
- 逻辑非(!):对一个条件取反。
- 如果条件为true,则返回 false
- 如果条件为false,则返回 true。
这些逻辑运算符通常用于复合条件的判断
,可以通过组合多个条件来确定程序的执行逻辑。逻辑与运算符和逻辑或运算符经常与条件语句(如if语句)结合使用,而逻辑非运算符可以用于取反一个条件的结果。
1 |
|
程序输出的结果为:
1 | flag = 0 |
5. 位运算符
所谓的位运算其实是就是针对于二进制数据的运算。在 C 语言中,常用的位运算符有以下几种:
按位与运算符:&
按位或运算符:|
按位异或运算符:^
按位取反运算符:~
左移运算符:<<
右移运算符:>>
5.1 按位与
按位与运算(&)是对两个操作数的每个二进制位进行与操作
,只有当对应位上的两个操作数都为1时,结果位才为1,否则为0。
关于按位与的特点可以精简为一句话:0 和任何数(0和1)都为 0。
1 | int a = 2; |
- 整形数 2 对应的二进制数是
10
- 整形数 4 对应的二进制数是
100
1 | 010 |
通过按位与操作,我们最终得到的结果为 0。
使用按位与可以快速判断整数的奇偶性,奇数的二进制表示的最低位为1,偶数的二进制表示的最低位为0。示例:
1 | int num = 9; |
5.2 按位或
按位或运算(|)是对两个操作数的每个二进制位进行或操作
,只要对应位上的两个操作数中至少有一个为1,结果位就为1,否则为0。
关于按位或的特点可以精简为一句话:1 和任何数(0和1)都为 1。
1 | int a = 2; |
- 整形数 2 对应的二进制数是
10
- 整形数 4 对应的二进制数是
100
1 | 010 |
通过按位或操作,我们最终得到的二进制结果为 110
,也就是十进制的 6。
5.3 按位异或
5.3.1 基本使用
按位异或运算(^)是对两个操作数的每个位进行异或操作
,当对应位上的两个操作数不同时,结果位为1,否则为0。
关于按位异或的特点可以精简为一句话:相同为0,不同为 1。
1 | int a = 2; |
- 整形数 2 对应的二进制数是
10
- 整形数 4 对应的二进制数是
110
1 | 010 |
通过按位异或操作,最终得到的二进制结果为 100
,也就是十进制的 4。
5.3.2 实际应用
按位异或(^)在实际应用中有以下两个常见用途(第二个个例子有循环, 可以在学完后面的知识点之后,再返回来消化吸收一下
):
交换两个变量的值:通过按位异或可以交换两个变量的值,而不需要使用临时变量。示例:
1
2
3
4
5
6int a = 5;
int b = 7;
a = a ^ b;
b = a ^ b;
a = a ^ b;
// 现在 a = 7, b = 5加密与解密:按位异或可用于简单的加密和解密算法。通过将数据与一个密钥按位异或,可以对数据进行加密。同样地,将加密后的数据再与密钥按位异或,可以解密数据。示例:
1
2
3
4
5
6
7
8
9
10
11
12
13unsigned char data[] = {0x45, 0x23, 0x7F, 0x18};
unsigned char key = 0xAB;
// 加密
for (int i = 0; i < sizeof(data); i++)
{
data[i] = data[i] ^ key;
}
// 解密
for (int i = 0; i < sizeof(data); i++)
{
data[i] = data[i] ^ key;
}
这些是按位异或运算符在实际应用中的几个常见用途,但也可以根据具体需求进行其他更复杂的运算和处理。按位异或操作的特性使得它在某些场景下非常有用,可以提供高效且简单的实现方式。
5.3 按位取反
按位取反运算(~)是对操作数的每个位进行取反操作
,将1变为0,将0变为1。
1 | int a = 1; |
接下来,我们将十进制数值转换为二进制进行分析:
1 | // 十进制的 1 |
根据上面的推导就可以得到如下结果:a = -2, b = -6
5.4 左移和右移
左移运算(<<)是将一个数的二进制表示向左移动
指定的位数,右侧空出的位用0填充。
右移运算(>>)是将一个数的二进制表示向右移动
指定的位数,左侧空出的位根据类型来填充:
- 对于有符号数,
使用算术右移
,用符号位填充左侧空位 - 对于无符号数,用 0 填充左侧空位
1 | int main() |
程序输出的结果为:
1 | a = 24, b = 8, c = -8 |
对于正数,右移一位相当于除以 2,向左移一位相当于乘以 2
在右移操作中,负数右移一位并不严格等于除以2,而是依赖于具体的编译器实现方式,因为 C 语言中没有明确规定。一种常见的实现方式是使用算术右移,即保留符号位并用符号位填充左侧空出的位。因此,负数右移一位并不一定等于除以2。
对于除以2的操作,除非对被除数是无符号整数,否则建议使用除法运算符(/)来达到目的。
这些位运算符可以用于位级操作和位级运算,用于对二进制数的位进行操作。它们在一些特定的场景下非常有用,如位掩码、位标志、图像处理等。
6. 运算符优先级
在C语言中,不同的运算符具有不同的优先级,这会影响表达式中运算符的计算顺序。下图是C语言中所有运算符的优先级顺序表:
在上面的表里边有关于运算符运算对象的多少
有三个分类:
一元运算符,即单目运算符
二元运算符,即双目运算符
三元运算符,即三目运算符
通过上表还可以看到,我们将C语言中的运算符的优先级划分了15个等级,其中很多运算符现阶段我们还没有接触到,随着学习的深入会经常查阅该表中的内容,记不住没关系,以后随用随查,用的多了自然就忘不掉了。
其中有一点需要大家一定要注意不要自作聪明,在一个语句或者表达式中使用太多的运算符,这样会降低代码的可读性,甚至自己都会被搞糊涂,远离bug珍爱生命。