C语言运算符有哪些?
按功能划分
在C语言中,运算符可以按照其功能进行分类。以下是各类运算符的详细列表:
- 算术运算符:这些运算符用于执行基本的数学运算。它们包括加法(+),减法(-),乘法(*),除法(/),和模(%)。
- +:加法运算符,将两个操作数相加。例如,5 + 3的结果是8。
- -:减法运算符,将第一个操作数减去第二个操作数。例如,5 – 3的结果是2。
- *:乘法运算符,将两个操作数相乘。例如,5 * 3的结果是15。
- /:除法运算符,将第一个操作数除以第二个操作数。例如,5 / 2的结果是2(整数除法)。
- %:取模运算符,返回第一个操作数除以第二个操作数的余数。例如,5 % 2的结果是1。
- 关系运算符:这些运算符用于比较两个值。它们包括等于(==),不等于(!=),大于(>),小于(<),大于等于(>=),小于等于(<=)。
- ==:等于运算符,如果两个操作数相等,则结果为1,否则为0。
- !=:不等于运算符,如果两个操作数不相等,则结果为1,否则为0。
- <:小于运算符,如果第一个操作数小于第二个操作数,则结果为1,否则为0。
- >:大于运算符,如果第一个操作数大于第二个操作数,则结果为1,否则为0。
- <=:小于或等于运算符,如果第一个操作数小于或等于第二个操作数,则结果为1,否则为0。
- >=:大于或等于运算符,如果第一个操作数大于或等于第二个操作数,则结果为1,否则为0。
- 逻辑运算符:这些运算符用于执行布尔逻辑运算。它们包括逻辑与(&&),逻辑或(||),逻辑非(!)。
- &&:逻辑与运算符,如果两个操作数都为true(非零),则结果为true,否则为false(零)。
- ||:逻辑或运算符,如果两个操作数中有一个为true,则结果为true,否则为false。
- !:逻辑非运算符,如果操作数为true,则结果为false,如果操作数为false,则结果为true。
- 位运算符:这些运算符用于操作位级数据。它们包括位与(&),位或(|),位异或(^),位非(~),左移(<<),右移(>>)。
- &:位与运算符,执行二进制“与”操作。
- |:位或运算符,执行二进制“或”操作。
- ^:位异或运算符,执行二进制“异或”操作。
- ~:位非运算符,执行二进制“非”操作(位反转)。
- <<:左移运算符,将操作数的二进制位向左移动指定的位数。
- >>:右移运算符,将操作数的二进制位向右移动指定的位数。
- 赋值运算符:这个运算符(=)用于将值赋给变量。
- 条件运算符:也被称为三元运算符,它是由问号(?)和冒号(:)符号组成的。
- 自增和自减运算符:这些运算符(++,–)用于增加或减少变量的值。
- sizeof运算符:此运算符(sizeof)用于获取存储类型的大小。
- 逗号运算符:用于链接两个或更多的独立表达式,使它们看起来像一个。
这就是C语言中运算符的分类。
复合赋值运算
在C语言中,复合赋值运算符是一种将赋值运算符(=)与其他运算符结合的简写形式。这些运算符不仅可以减少代码的编写量,还可以在某些情况下增加代码的清晰度。以下是C语言中常见的复合赋值运算符及其说明:
- += 加法赋值运算符:把右操作数加上左操作数的结果赋值给左操作数。a += b; // 等价于 a = a + b;
- -= 减法赋值运算符:从左操作数中减去右操作数后的结果赋值给左操作数。a -= b; // 等价于 a = a – b;
- *= 乘法赋值运算符:把左操作数与右操作数的乘积赋值给左操作数。a *= b; // 等价于 a = a * b;
- /= 除法赋值运算符:把左操作数除以右操作数的商赋值给左操作数。a /= b; // 等价于 a = a / b; (注意:b不能为0)
- %= 模除赋值运算符:把左操作数除以右操作数的余数赋值给左操作数。a %= b; // 等价于 a = a % b; (注意:b不能为0)
- <<= 左移赋值运算符:把左操作数向左移动指定位数的结果赋值给左操作数。a <<= 2; // 等价于 a = a << 2;
- >>= 右移赋值运算符:把左操作数向右移动指定位数的结果赋值给左操作数。a >>= 2; // 等价于 a = a >> 2;
- &= 按位与赋值运算符:对左和右操作数进行按位与操作后的结果赋值给左操作数。a &= b; // 等价于 a = a & b;
- ^= 按位异或赋值运算符:对左和右操作数进行按位异或操作后的结果赋值给左操作数。a ^= b; // 等价于 a = a ^ b;
- |= 按位或赋值运算符:对左和右操作数进行按位或操作后的结果赋值给左操作数。a |= b; // 等价于 a = a | b;
使用复合赋值运算符可以使代码更简洁。例如,在进行累加或累乘等操作时,使用复合赋值运算符可以直观地表达操作的意图,同时减少了代码的书写量。
求址运算符
在C语言中,求址运算符(Address-of Operator)是一个一元运算符,用符号&表示。它的作用是获取其操作数的内存地址。这个运算符非常重要,因为它允许程序直接操作内存地址,从而与指针一起使用,实现对变量的间接访问和操作。
假设我们有一个变量int a = 5;,我们想要获取这个变量的内存地址,可以这样使用求址运算符:
#include <stdio.h> int main() { int a = 5; int *p = &a; // 使用求址运算符获取a的地址,并将其赋值给指针p printf("The value of a is: %d\n", a); printf("The address of a is: %p\n", (void*)p); return 0; }
在这个示例中,&a将获得变量a的内存地址,然后我们将这个地址赋给指针变量p。注意,我们在打印地址时将p转换为void*类型,这是因为%p格式化输出期待的是一个void*类型的参数。
求址运算符和指针紧密相关。指针是存储内存地址的变量。通过使用求址运算符,可以将一个变量的地址赋给指针。然后,可以通过指针间接访问或修改原始变量的值。
注意事项
- 求址运算符只能应用于存储在内存中的对象(如变量),而不能用于字面值或表达式的结果。例如,&5或&(x+y)在C语言中是非法的。
- 当使用求址运算符时,确保对应的指针类型与原变量类型匹配。例如,如果变量是int类型,则指针应该是int*类型。
求址运算符是C语言中实现指针功能,进而实现内存直接访问和操作的基础之一。正确理解和使用求址运算符对于编写高效和灵活的C程序至关重要。
取值运算符
在C语言中,取值运算符(Dereference Operator),也称为间接访问运算符,用*表示。它与求址运算符&相对应,用于访问指针变量所指向的内存地址中存储的值。简而言之,如果你有一个指向某个数据的指针,使用取值运算符可以获取该指针指向地址上的数据值。
假设我们有一个指针变量p,它指向了一个整型变量a的地址,我们可以通过*p来访问并获取a的值。
#include <stdio.h> int main() { int a = 5; int *p = &a; // p 存储了 a 的地址 // 使用取值运算符访问 p 指向的地址上的值 printf("The value of a is: %d\n", *p); // 通过指针 p 更改 a 的值 *p = 10; printf("The new value of a is: %d\n", a); return 0; }
在这个示例中,*p首先被用来获取p指向的内存地址上存储的值(即a的值),然后又通过*p = 10;来更改该地址上存储的值,导致a的值变为10。
取值运算符是解引用指针或访问指针指向的数据的关键。它允许程序不仅仅是操作数据的地址,还能操作地址中的实际数据。这是实现动态数据结构(如链表和树)以及进行低级内存访问的基础。
注意事项
- 在使用取值运算符前,确保指针指向的地址是有效的。访问无效或未初始化的指针指向的内存可能导致未定义行为,包括程序崩溃。
- 取值运算符可以用于多层指针(指针的指针),每次使用都降低一层间接性。例如,对于int **pp;,*pp是int*类型,而**pp是int类型。
取值运算符是理解和使用C语言指针的核心。通过指针和取值运算符的配合使用,程序员可以编写出更高效、灵活且直接操作底层数据的代码。
强制转化
在C语言中,强制类型转换(或显式类型转换)是一种操作,它允许程序员在不同数据类型之间显式转换变量的类型。这通常是为了在执行操作时保证数据类型的兼容性,或为了避免隐式类型转换可能导致的不精确或错误。
强制类型转换的语法非常简单,如下所示:
(目标类型) 表达式
这里,“目标类型”是你希望表达式转换成的类型,而“表达式”是要被转换的值或表达式。
假设我们有一个整型变量和一个浮点型变量,我们需要执行一个精确的除法操作并且结果也需要是浮点数,可以通过强制类型转换来实现:
#include <stdio.h> int main() { int a = 5; float b = 2.0; // 未使用强制转换,结果将不会包含小数部分 float result1 = a / b; printf("Result without casting: %f\n", result1); // 使用强制转换 float result2 = (float)a / b; printf("Result with casting: %f\n", result2); return 0; }
在这个例子中,通过将a强制转换为float类型,确保了除法操作是在浮点数之间进行的,这样结果result2就能正确地包含小数部分。
注意事项
- 使用强制类型转换时应小心,尤其是在将较大的数据类型转换为较小的数据类型时,可能会导致数据丢失或溢出。
- 强制类型转换可以影响程序的可读性,因此应该在不影响程序清晰度的情况下谨慎使用。
- 有些自动(隐式)类型转换会在特定操作中自动发生,但显式类型转换(强制转换)是明确指示编译器进行特定类型转换的一种方式。
强制类型转换是C语言中一个非常有用的工具,可以帮助处理各种不同类型间的运算和操作,但使用时需要注意确保数据的正确性和程序的清晰度。
按操作数划分
在C语言中,运算符还可以根据其操作数的数量进行分类。具体来看:
- 单目运算符:这些运算符只需要一个操作数。包括了一元加号(+)、一元减号(-)、逻辑非(!)、按位取反(~)、自增(++)、自减(–)以及地址运算符(&)和取值运算符(*)等。
- 双目运算符:这些运算符需要两个操作数。例如,算术运算符(+、-、*、/、%)、关系运算符(==、!=、>、<、>=、<=)、逻辑运算符(&&、||)、位运算符(&、|、^)、赋值运算符(=)及其组合(+=、-= 等)以及移位运算符(<<、>>)等。
- 三目运算符:这种运算符需要三个操作数,C语言中唯一的三目运算符就是条件运算符(?:)。
这就是按照操作数的数量对C语言中的运算符进行分类的情况。
按结合方向划分
在C语言中,运算符也可以根据结合性或结合方向进行分类,结合性决定了具有相同优先级的运算符的执行顺序。具体来说,有:
- 左结合运算符:从左至右进行计算。这包括赋值运算符(=、+=、-=、=、/=、%=等)、逻辑运算符(&&、||)、关系运算符(==、!=、>、<、>=、<=)、位运算符(&、|、^)、算术运算符(+、-、、/、%)、移位运算符(<<、>>)以及条件运算符(?:)的第二和第三部分等。
- 右结合运算符:从右至左进行计算。这包括一元运算符(+、-、!、~)、自增和自减运算符(++、–)、地址运算符和解引用运算符(&、*)、sizeof运算符以及条件运算符(?:)的第一部分等。
这就是按结合性对C语言中的运算符进行分类的情况。
运算符的优先级
在C语言中,运算符的优先级决定了表达式中操作数的组合方式。以下是C语言运算符的优先级列表,从高到低:
- 括号运算符 ()
- 一元运算符,如 +(正)、-(负)、++(前自增)、–(前自减)、!(逻辑非)、~(按位取反)、sizeof等
- 二元运算符,如 *(乘法)、/(除法)、%(取模)
- 二元运算符,如 +(加法)、-(减法)
- 移位运算符,如 <<(左移)、>>(右移)
- 关系运算符,如 <、<=、>、>=
- 等于和不等于运算符,如 ==、!=
- 位运算符,如 &(按位与)
- 位运算符,如 ^(按位异或)
- 位运算符,如 |(按位或)
- 逻辑运算符,如 &&(逻辑与)
- 逻辑运算符,如 ||(逻辑或)
- 三元运算符,如 ?:
- 赋值运算符,如 =、+=、-=、*=、/=、%=、<<=、>>=、&=、^=、|=
- 逗号运算符,如 ,
如果表达式中有优先级相同的运算符,那么执行顺序由它们的结合性决定。如果优先级不同,那么优先级高的运算符先执行。如果你不确定运算符的优先级,或者表达式很复杂,最好使用括号来确保运算的正确性。