引言
在C语言的浩瀚宇宙中,运算符如同点亮星辰的魔法棒,它们不仅连接着数据的海洋,更驱动着程序的逻辑流转。从基础的算术运算到复杂的位操作,每一个运算符都承载着特定的功能,是构建程序逻辑的基石。掌握C语言的运算符,就如同手握开启编程世界大门的钥匙,让你能够自如地编写出高效、精准的代码。本文将带你深入探索C语言的运算符世界一一解析它们的奥秘,助你在编程之路上越走越远。
算术运算符
运算符 | 描述 | 示例 |
---|---|---|
+ |
加法运算符,用于将两个数相加 | int result = 5 + 3; // 结果为 8 |
- |
减法运算符,用于从一个数中减去另一个数 | int result = 10 - 4; // 结果为 6 |
* |
乘法运算符,用于将两个数相乘 | int result = 3 * 4; // 结果为 12 |
/ |
除法运算符,用于将第一个数除以第二个数 | int quotient = 10 / 2; // 结果为 5 float division = 10.0 / 3.0; // 结果为 3.333... |
% |
取模运算符(求余),返回两数相除的余数 | int remainder = 10 % 3; // 结果为 1 |
++ |
自增运算符,将变量的值增加1 | int a = 5; a++; // a 的值变为 6 int b = 5; ++b; // b 的值同样变为 6 |
-- |
自减运算符,将变量的值减少1 | int c = 5; c--; // c 的值变为 4 int d = 5; --d; // d 的值同样变为 4 |
注意:
- 当使用
/
运算符进行整数除法时,结果会向下取整,即舍弃小数部分。 %
运算符的操作数必须是整数。- 自增(
++
)和自减(--
)运算符可以放在变量之前(前缀形式)或之后(后缀形式),但在表达式中的行为可能有所不同。前缀形式会先增加(或减少)变量的值,然后再进行其他操作;后缀形式则会先进行其他操作,然后再增加(或减少)变量的值。但在这个表格的示例中,我们主要关注它们的基本用法。
关系运算符
运算符 | 描述 | 示例 |
---|---|---|
== |
等于,比较两个值是否相等 | if (5 == 3) { /* 这部分代码不会执行 */ } if (5 == 5) { /* 这部分代码会执行 */ } |
!= |
不等于,比较两个值是否不相等 | if (5 != 3) { /* 这部分代码会执行 */ } if (5 != 5) { /* 这部分代码不会执行 */ } |
> |
大于,比较第一个值是否大于第二个值 | if (5 > 3) { /* 这部分代码会执行 */ } if (5 > 5) { /* 这部分代码不会执行 */ } |
< |
小于,比较第一个值是否小于第二个值 | if (3 < 5) { /* 这部分代码会执行 */ } if (5 < 3) { /* 这部分代码不会执行 */ } |
>= |
大于等于,比较第一个值是否大于或等于第二个值 | if (5 >= 5) { /* 这部分代码会执行 */ } if (3 >= 5) { /* 这部分代码不会执行 */ } |
<= |
小于等于,比较第一个值是否小于或等于第二个值 | if (3 <= 5) { /* 这部分代码会执行 */ } if (5 <= 3) { /* 这部分代码不会执行 */ } |
注意:
- 关系运算符用于比较两个值,并返回一个布尔结果(在C语言中,实际上是以整数形式返回,其中
0
表示false
,非0
值表示true
)。 - 这些运算符经常与
if
、while
、for
等控制流语句一起使用,以根据条件执行不同的代码块。 - 在进行比较时,确保比较的数据类型兼容,否则可能会引发编译错误或意外的行为。例如,将整数与浮点数直接进行比较通常不是一个好主意,除非你有意为之并了解可能的结果。
逻辑运算符
运算符 | 描述 | 示例 |
---|---|---|
&& |
逻辑与(AND),仅当两个操作数都为真时,结果才为真 | if (a > 0 && b > 0) { /* 当a和b都大于0时执行 */ } |
|| |
逻辑或(OR),当两个操作数中至少有一个为真时,结果就为真 | if (a > 0 || b > 0) { /* 当a或b中至少有一个大于0时执行 */ } |
! |
逻辑非(NOT),用于反转操作数的真假值 | if (!a) { /* 当a为假时执行 */ } 或 if (!(a > 0)) { /* 当a不大于0时执行 */ } |
注意:
- 逻辑运算符通常用于控制流语句(如
if
、while
、for
)中,以根据多个条件的组合来决定是否执行某个代码块。 - 在C语言中,真值通常表示为非零值,而假值则表示为
0
。因此,逻辑运算符的操作数可以是任何整数表达式,其真假值取决于表达式的计算结果。 - 使用逻辑运算符时,应注意运算符的优先级和结合性。通常,
!
运算符的优先级最高,&&
和||
运算符的优先级低于关系运算符和算术运算符,但高于赋值运算符。此外,&&
和||
运算符是左结合的,即它们从左到右评估操作数。 - 逻辑与(
&&
)运算符具有短路行为,即如果第一个操作数为假(即0
),则不会评估第二个操作数,因为整个表达式的结果已经确定为假。同样,逻辑或(||
)运算符也具有短路行为,即如果第一个操作数为真(即非0
),则不会评估第二个操作数,因为整个表达式的结果已经确定为真。这种短路行为有时可以用于避免不必要的计算或潜在的副作用。
位运算符
运算符 | 描述 | 示例 |
---|---|---|
& |
按位与(AND),对两个数的二进制表示进行逐位与操作,只有对应的两个二进位均为1时,结果位才为1 | int a = 5; // 二进制: 0101 int b = 3; // 二进制: 0011 int c = a & b; // 结果: 1, 二进制: 0001 |
| |
按位或(OR),对两个数的二进制表示进行逐位或操作,只要对应的两个二进位中有一个为1时,结果位就为1 | int a = 5; // 二进制: 0101 int b = 3; // 二进制: 0011 int c = a | b; // 结果: 7, 二进制: 0111 |
^ |
按位异或(XOR),对两个数的二进制表示进行逐位异或操作,当对应的两个二进位相异时,结果位为1 | int a = 5; // 二进制: 0101 int b = 3; // 二进制: 0011 int c = a ^ b; // 结果: 6, 二进制: 0110 |
~ |
按位取反(NOT),对数的二进制表示进行逐位取反操作,即0变1,1变0 | int a = 5; // 二进制: 0101 int b = ~a; // 结果: -6, 二进制(补码): 11111010(注意:结果以补码形式存储,实际值需考虑数据类型和符号位) |
<< |
左移(Left Shift),将数的二进制表示向左移动指定的位数,左侧超出的位将被丢弃,右侧新增的位将用0填充 | int a = 5; // 二进制: 0101 int b = a << 2; // 结果: 20, 二进制: 10100 |
>> |
右移(Right Shift),将数的二进制表示向右移动指定的位数,对于有符号数,左侧新增的位将用符号位填充(即正数用0填充,负数用1填充),右侧超出的位将被丢弃 | int a = 5; // 二进制: 0101 int b = a >> 2; // 结果: 1, 二进制: 0001 int c = -5; // 假设为32位整数,二进制(补码): 11111111 11111111 11111111 11111011 int d = c >> 2; // 结果: -2, 二进制(补码): 11111111 11111111 11111111 11111110 |
注意:
- 位运算符的操作数通常是整数类型(如
int
、char
等),不能是浮点类型(如float
、double
)。 - 在进行位移操作时,特别是右移操作,对于有符号数,不同编译器或平台可能有不同的行为(即算术右移或逻辑右移),因此在跨平台编程时需要特别注意。
- 位运算符常用于底层编程、硬件编程、性能优化等场景,它们允许程序员直接对数据的二进制表示进行操作,从而实现高效的数据处理和算法实现。
- 示例中的结果以十进制形式给出,但为了说明位运算的过程,同时也给出了二进制形式的说明(对于取反操作,由于结果以补码形式存储,因此直接给出了补码形式的二进制表示和对应的十进制值)。在实际编程中,需要注意数据类型和符号位对结果的影响。
赋值运算符
运算符 | 描述 | 示例 |
---|---|---|
= |
简单的赋值运算符,用于将右侧表达式的值赋给左侧的变量 | int a = 5; // 将5赋值给变量a |
+= |
加法赋值运算符,将右侧表达式的值与左侧变量的值相加,然后将结果赋值给左侧变量 | a += 3; // 相当于 a = a + 3; 假设a之前的值为5,则执行后a的值为8 |
-= |
减法赋值运算符,将左侧变量的值减去右侧表达式的值,然后将结果赋值给左侧变量 | a -= 2; // 相当于 a = a - 2; 假设a之前的值为8,则执行后a的值为6 |
*= |
乘法赋值运算符,将左侧变量的值与右侧表达式的值相乘,然后将结果赋值给左侧变量 | a *= 2; // 相当于 a = a * 2; 假设a之前的值为6,则执行后a的值为12 |
/= |
除法赋值运算符,将左侧变量的值除以右侧表达式的值,然后将结果赋值给左侧变量 | a /= 2; // 相当于 a = a / 2; 假设a之前的值为12,则执行后a的值为6 |
%= |
取模赋值运算符,将左侧变量的值对右侧表达式的值取模,然后将结果赋值给左侧变量 | a %= 3; // 相当于 a = a % 3; 假设a之前的值为6,则执行后a的值为0 |
<<= |
左移赋值运算符,将左侧变量的二进制表示向左移动指定的位数(由右侧表达式给出),然后将结果赋值给左侧变量 | a <<= 1; // 相当于 a = a << 1; 假设a之前的值为6(二进制: 0110),则执行后a的值为12(二进制: 1100) |
>>= |
右移赋值运算符,将左侧变量的二进制表示向右移动指定的位数(由右侧表达式给出),然后将结果赋值给左侧变量 | a >>= 1; // 相当于 a = a >> 1; 假设a之前的值为12(二进制: 1100),则执行后a的值为6(二进制: 0110),对于有符号数,注意符号位的扩展 |
&= |
按位与赋值运算符,对左侧变量的值和右侧表达式的值进行按位与操作,然后将结果赋值给左侧变量 | a &= 3; // 相当于 a = a & 3; 假设a之前的值为12(二进制: 1100),则执行后a的值为0(二进制: 0000),因为1100 & 0011 = 0000 |
|= |
按位或赋值运算符,对左侧变量的值和右侧表达式的值进行按位或操作,然后将结果赋值给左侧变量 | a |= 3; // 相当于 a = a | 3; 假设a之前的值为4(二进制: 0100),则执行后a的值为7(二进制: 0111),因为0100 | 0011 = 0111 |
^= |
按位异或赋值运算符,对左侧变量的值和右侧表达式的值进行按位异或操作,然后将结果赋值给左侧变量 | a ^= 3; // 相当于 a = a ^ 3; 假设a之前的值为4(二进制: 0100),则执行后a的值为7(二进制: 0111),因为0100 ^ 0011 = 0111 |
注意:
- 赋值运算符用于将表达式的值存储到变量中。
- 复合赋值运算符(如
+=
、-=
等)是先进行指定的算术或位运算,然后将结果赋值给左侧的变量,这种方式可以使代码更简洁。 - 在使用位运算符(如
<<=
、>>=
、&=
、\|=
、^=
)时,需要注意操作数的数据类型和符号位的影响,特别是在进行右移操作时。 - 赋值运算的结果通常是赋值给左侧的变量,但某些情况下(如在表达式中使用赋值运算符),其结果也可以被用于其他目的。然而,为了代码的可读性和可维护性,建议避免在需要计算结果的表达式中使用赋值运算符。
杂项运算符
运算符 | 描述 | 示例 |
---|---|---|
sizeof |
用于获取变量或数据类型所占内存的大小(以字节为单位) | size_t size = sizeof(int); // 获取int类型所占的字节数,结果通常为4(取决于编译器和平台) |
& (地址运算符) |
获取变量的内存地址 | int a = 5; int* ptr = &a; // ptr存储了变量a的内存地址 |
* (解引用/间接访问运算符) |
通过指针访问其所指向的内存地址中的值 | int* ptr = &a; int value = *ptr; // value的值为5,即a的值 |
?: (条件运算符/三元运算符) |
根据条件表达式的真假来选择两个值中的一个 | int a = 10, b; b = (a > 5) ? 20 : 30; // b的值为20,因为a大于5 |
注意:
-
sizeof
运算符的返回值类型为size_t
,这是一个无符号整数类型,用于表示对象的大小。 -
地址运算符
&
用于获取变量的内存地址,其结果是一个指向该变量类型的指针。 -
解引用/间接访问运算符
*
用于通过指针访问其所指向的内存地址中的值。如果指针未初始化或指向无效的内存地址,则解引用该指针可能导致未定义行为。 -
条件运算符
?:
是一个三元运算符,它接受三个操作数:条件表达式、当条件为真时返回的值、以及当条件为假时返回的值。其优先级低于关系运算符和算术运算符,但高于赋值运算符。 -
杂项运算符在C语言中扮演着重要的角色,它们提供了对内存地址的直接操作、条件选择等功能,是编写高效、灵活C语言程序的关键。然而,由于它们直接操作内存地址或进行条件选择,因此在使用时需要格外小心,以避免引入错误或安全问题。
运算符优先级
优先级 | 运算符 | 描述 | 用法示例 |
---|---|---|---|
1 | 括号 () |
用于改变运算的优先级 | (a + b) * c |
2 | 自增 ++ 、自减 -- 、正负号 + 、- 、逻辑非 ! 、按位取反 ~ |
单目运算符,作用于单个操作数 | ++a , --b , +5 , -3 , !flag , ~x |
3 | 乘法 * 、除法 / 、取模 % |
双目运算符,用于算术运算 | a * b , c / d , e % f |
4 | 加法 + 、减法 - |
双目运算符,用于算术运算 | g + h , i - j |
5 | 左移 << 、右移 >> |
双目运算符,用于位运算 | k << 2 , l >> 1 |
6 | 关系运算符(大于 > , 大于等于 >= , 小于 < , 小于等于 <= ) |
双目运算符,用于比较操作数 | m > n , o >= p , q < r , s <= t |
7 | 等于 == 、不等于 != |
双目运算符,用于比较操作数是否相等 | u == v , w != x |
8 | 按位与 & |
双目运算符,用于位运算 | y & z |
9 | 按位异或 ^ |
双目运算符,用于位运算 | a ^ b |
10 | 按位或 | |
双目运算符,用于位运算 | c | d |
11 | 逻辑与 && |
双目运算符,用于逻辑运算 | e && f |
12 | 逻辑或 || |
双目运算符,用于逻辑运算 | g || h |
13 | 条件运算符 ?: |
三目运算符,根据条件选择两个值中的一个 | i > 0 ? i : -i |
14 | 赋值运算符 = 、+= 、-= 、*= 、/= 、%= 、&= 、^= 、|= 、<<= 、>>= |
用于将值赋给变量或进行复合赋值 | j = 5 , k += 3 |
15 | 逗号运算符 , |
用于分隔表达式,并返回最后一个表达式的值 | m = 1, n = 2, m + n (结果为3,但m和n也被赋值) |
注意: |
-
运算符优先级决定了在一个表达式中各个运算符的执行顺序。当表达式中存在多个运算符时,优先级高的运算符会先进行计算。
-
可以通过使用括号()来改变运算符的优先级,使得括号内的表达式先被计算。
-
赋值运算符的优先级相对较低,这意味着在复杂的表达式中,赋值操作通常会在其他算术、逻辑或位运算之后进行。
-
逗号运算符,用于分隔多个表达式,并返回最后一个表达式的值。它在所有运算符中具有最低的优先级,因此逗号两边的表达式会按照从左到右的顺序依次计算。
请注意,虽然这个表格提供了C语言运算符优先级的基本概述,但在实际编程中,为了代码的可读性和易于理解,建议尽量使用括号来明确表达式的计算顺序。
标签:变量,--,C语言,运算符,二进制,int,表达式,赋值 From: https://www.cnblogs.com/kdgoat/p/18337695