前言:
在 C 语言的编程体系中,操作符就像是一个个精密的齿轮,相互配合驱动着程序的运转。熟练掌握操作符的使用,不仅能编写出高效、简洁的代码,还能深入理解程序运行的底层逻辑。接下来,让我们一同深入探索 C 语言操作符的奥秘
目录
一、操作符的分类全景
二、算术操作符:数值运算的基石
三、移位操作符:二进制世界的舞者
四、位操作符:深入二进制的核心
五、赋值操作符:数据传递的纽带
六、单目操作符:功能强大的 “独行侠”
七、关系操作符和逻辑操作符:程序逻辑的导航仪
八、条件操作符和逗号表达式:灵活编程的秘籍
九、下标引用、函数调用和结构成员操作符:C 语言中的重要工具
1、下标引用操作符 []
2、函数调用操作符 ()
3、结构成员操作符 . 和 ->
十、表达式求值:背后的规则与陷阱
一、操作符的分类全景
C 语言的操作符种类丰富,涵盖算术操作符、移位操作符、位操作符、赋值操作符、单目操作符、关系操作符、逻辑操作符、条件操作符、逗号表达式,以及下标引用、函数调用和结构成员操作符等。它们各司其职,在不同的编程场景中发挥着关键作用
二、算术操作符:数值运算的基石
算术操作符是编程中最常用的操作符之一,包括+
(加法)、-
(减法)、*
(乘法)、/
(除法)和%
(取余)。除了%
操作符仅适用于整数运算外,其他操作符对整数和浮点数均适用,在进行除法运算时,若两个操作数都是整数,执行的是整数除法,结果会舍去小数部分。例如:
上述代码中,7 / 3
的结果为2
,因为整数除法会舍弃小数部分。
若操作数中有浮点数,则执行浮点数除法,结果会保留小数部分:
在这段代码里,7.0 / 3
的结果为2.333333
,这体现了浮点数除法的特性。
%
操作符用于计算两个整数相除后的余数,例如:
这里7 % 3
的结果是1
,即7
除以3
的余数 。
三、移位操作符:二进制世界的舞者
移位操作符分为左移操作符 <<
和右移操作符 >>
,它们直接对二进制位进行操作。左移操作符的规则是左边抛弃,右边补 0。例如,将整数5
(二进制表示为:00000000000000000000000000000101
)左移一位:
执行代码后,shiftedLeft
的值为10
,因为左移一位后,二进制变成00000000000000000000000000001010
,转换为十进制就是10
。
右移操作符的移位规则较为复杂,分为逻辑移位和算术移位。
逻辑移位:左边用 0 填充,右边丢弃;
算数右移:左边用原数的符号位填充,右边丢弃。例如,对于负数-1
(补码为11111111111111111111111111111111
):
警告⚠ : 对于移位运算符,不要移动负数位,这个是标准未定义的
四、位操作符:深入二进制的核心
位操作符包括按位与&
、按位或|
和按位异或^
,操作数必须是整数。这些操作符在处理二进制数据时非常有用。
按位与操作可以用于判断一个数的某些位是否为 1。例如,判断一个整数的最低位是否为 1:
在这段代码中,num & 1
将num
的二进制表示与00000000000000000000000000000001
进行按位与操作。如果结果不为 0,则说明num
的最低位是 1。
练习1 :不能创建临时变量(第三个变量),实现两个数的交换:
这段代码利用按位异或的特性,巧妙地实现了两个数的交换,避免了使用额外的临时变量,提高了代码的效率
练习2 :求一个整数存储在内存中的二进制中1的个数
五、赋值操作符:数据传递的纽带
赋值操作符=
用于将右侧的值赋给左侧的变量,它还支持连续赋值。例如:
在这段代码中,a = b = c = 10
从右向左依次赋值,最终a
、b
、c
的值都为10
。
此外,还有复合赋值符,如+=
、-=
、*=
、/=
等,这些操作符可以简化代码。例如,a += 5
等价于a = a + 5
:
使用复合赋值符不仅代码更简洁,还能提高编程效率。
六、单目操作符:功能强大的 “独行侠”
单目操作符只需要一个操作数,功能多样。例如,逻辑反操作!
可以将真(非 0)变为假(0),将假变为真:
sizeof
操作符用于计算操作数的类型长度(以字节为单位):
这里sizeof(num)
返回num
所占用的字节数,sizeof(char)
返回char
类型占用的字节数。不同系统下,这些值可能会有所不同,但在常见的 32 位和 64 位系统中,int
通常为 4 字节,char
为 1 字节
七、关系操作符和逻辑操作符:程序逻辑的导航仪
关系操作符用于比较两个值的大小关系,包括>
(大于)、>=
(大于等于)、<
(小于)、<=
(小于等于)、!=
(不等于)和==
(等于)。在使用时,要特别注意==
和=
的区别,避免因写错而导致逻辑错误。例如:
这段代码通过关系操作符判断a
和b
的大小关系,并根据判断结果执行相应的代码块。
逻辑操作符包括逻辑与&&
和逻辑或||
,用于组合多个条件。逻辑与操作只有当所有条件都为真时,结果才为真;逻辑或操作只要有一个条件为真,结果就为真。例如:
在这段代码中,&&
和||
分别组合了多个条件,控制程序的执行流程
八、条件操作符和逗号表达式:灵活编程的秘籍
条件操作符exp1? exp2 : exp3
是一种简洁的选择结构,根据exp1
的真假来决定执行exp2
还是exp3
。例如,求两个数中的较大值:
这段代码使用条件操作符简洁地求出了a
和b
中的较大值(如果a>b为真就执行a,反之,执行b)
逗号表达式exp1, exp2, exp3, …expN
从左向右依次执行,整个表达式的结果是最后一个表达式的结果。例如:
在这段代码中,逗号表达式先执行a++
和b++
,然后计算a + b
的值并赋给c
。最终c
的值为5
,因为a++
和b++
执行后,a
变为2
,b
变为3
,a + b
即为5
九、下标引用、函数调用和结构成员操作符:C 语言中的重要工具
在 C 语言丰富的操作符家族中,下标引用、函数调用和结构成员操作符是进行数据访问和函数执行的关键元素,它们各自有着独特的功能和使用方式
1、下标引用操作符 []
下标引用操作符用于访问数组中的元素。它的操作数为一个数组名和一个索引值。
在 C 语言中,数组是一种重要的数据结构,用于存储多个相同类型的数据。通过下标引用操作符,可以方便地访问数组中的特定元素。例如:
在上述代码中,[]
的两个操作数分别是数组名 arr
和索引值 9
。需要注意的是,C 语言中的数组索引是从 0 开始的,这意味着对于一个长度为 n
的数组,合法的索引范围是 0
到 n - 1
。如果使用了超出这个范围的索引,会导致未定义行为,可能引发程序崩溃或产生错误的结果。
此外,下标引用操作符还可以与指针结合使用。在 C 语言中,数组名在很多情况下会被隐式转换为指向数组首元素的指针。因此,arr[i]
和 *(arr + i)
是等价的,它们都表示访问数组 arr
中索引为 i
的元素。例如:
2、函数调用操作符 ()
函数调用操作符用于调用函数。它接受一个或者多个操作数,第一个操作数是函数名,剩余的操作数就是传递给函数的参数。
函数是 C 语言中实现模块化编程的重要手段,通过函数调用操作符,可以执行预先定义好的函数逻辑。例如:
在上述代码中,add
是函数名,作为函数调用操作符 ()
的第一个操作数,3
和 5
是传给 add
函数的参数。函数调用操作符会触发函数的执行,函数执行完毕后会返回一个值(在这个例子中,add
函数返回两个参数的和),可以将这个返回值赋值给变量或者进行其他操作。
函数调用操作符的灵活性很高,不仅可以传递常量作为参数,还可以传递变量、表达式等。同时,函数也可以没有参数,例如:
在这个例子中,printHello
函数没有参数,调用时只需要使用函数名和空的函数调用操作符 ()
即可。
3、结构成员操作符 .
和 ->
结构是 C 语言中用于将不同类型的数据组合在一起的一种自定义数据类型。结构成员操作符用于访问结构中的成员。
'.' 操作符:当使用结构变量来访问成员时,使用 .
操作符。例如:
在上述代码中,stu
是 struct Student
类型的变量,通过 .
操作符,stu.name
访问结构体中的 name
成员,stu.age
访问 age
成员
->
操作符:当使用指向结构的指针来访问成员时,使用 ->
操作符。例如:
在这个例子中,ptr
是指向 struct Student
类型的指针,通过 ->
操作符,ptr->name
和 ptr->age
分别访问结构体 stu
中的 name
和 age
成员。实际上,ptr->name
等价于 (*ptr).name
,->
操作符提供了一种更简洁的方式来通过指针访问结构体成员。
下标引用、函数调用和结构成员操作符在 C 语言编程中扮演着不可或缺的角色。熟练掌握它们的使用方法,能够帮助开发者更加高效地进行数据处理和函数调用,构建出结构清晰、功能强大的程序。
十、表达式求值:背后的规则与陷阱
表达式求值的顺序受到操作符优先级、结合性以及是否控制求值顺序等因素的影响。在进行表达式求值时,还可能涉及隐式类型转换和算术转换。
隐式类型转换是为了保证整型运算的精度,会将字符和短整型操作数在使用前转换为普通整型。例如:
字符 'A'
和 'B'
在参与 a + b
运算时,由于 C 语言的整型算术运算总是至少以缺省整型类型(通常为 int
类型)的精度来进行,所以会先进行整型提升。'A'
的 ASCII 码值是 65,'B'
的 ASCII 码值是 66 ,它们在进行整型提升时,会将其对应的 ASCII 码值按照 int
类型的长度进行扩展:
- 对于有符号
char
类型(很多编译器下默认char
是有符号的),如果char
类型的最高位(符号位)为 0,就在高位补 0;如果最高位为 1,就在高位补 1(有符号位补符号位)。 - 对于无符号
char
类型,无论原char
类型数据的最高位是什么,都在高位补 0(没符号位补0)。
这里 'A'
和 'B'
的 ASCII 码值对应的二进制最高位都是 0,所以整型提升后高位补 0,然后再进行加法运算,65 + 66 = 131
,最终 result
的值为 131。
但要注意,不合理的算术转换可能会导致精度丢失等问题。例如:
在这段代码中,float
类型的f
转换为int
类型时,小数部分会被截断,导致精度丢失。
有些表达式由于操作符优先级和结合性无法确定唯一的计算路径,结果是不可预测的,属于有问题的表达式。例如:
在不同的编译器中,这段代码的结果可能不同,因为i++
和++i
的执行顺序无法通过操作符的优先级和结合性确定。在编写代码时,应尽量避免写出这样的表达式,确保程序的正确性和稳定性。
C 语言操作符是编程中不可或缺的一部分,深入理解和熟练运用它们,能够帮助我们编写出更加高效、稳定的程序。希望通过本文的介绍,大家对 C 语言操作符有更全面、更深入的认识,在编程实践中能够灵活运用这些知识,解决各种实际问题。