4

C语言学习之运算符

 1 month ago
source link: https://www.biaodianfu.com/c-operators.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

C语言运算符有哪些?

按功能划分

c-operators.png

在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;
#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;
#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;
#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语言中的运算符进行分类的情况。

运算符的优先级

youxianji.png

在C语言中,运算符的优先级决定了表达式中操作数的组合方式。以下是C语言运算符的优先级列表,从高到低:

  • 括号运算符 ()
  • 一元运算符,如 +(正)、-(负)、++(前自增)、–(前自减)、!(逻辑非)、~(按位取反)、sizeof等
  • 二元运算符,如 *(乘法)、/(除法)、%(取模)
  • 二元运算符,如 +(加法)、-(减法)
  • 移位运算符,如 <<(左移)、>>(右移)
  • 关系运算符,如 <、<=、>、>=
  • 等于和不等于运算符,如 ==、!=
  • 位运算符,如 &(按位与)
  • 位运算符,如 ^(按位异或)
  • 位运算符,如 |(按位或)
  • 逻辑运算符,如 &&(逻辑与)
  • 逻辑运算符,如 ||(逻辑或)
  • 三元运算符,如 ?:
  • 赋值运算符,如 =、+=、-=、*=、/=、%=、<<=、>>=、&=、^=、|=
  • 逗号运算符,如 ,

如果表达式中有优先级相同的运算符,那么执行顺序由它们的结合性决定。如果优先级不同,那么优先级高的运算符先执行。如果你不确定运算符的优先级,或者表达式很复杂,最好使用括号来确保运算的正确性。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK