13、运算符

厨子大约 8 分钟C语言基础程序程序厨

运算符是执行各种操作的核心工具,它们定义了如何在程序中对数据进行处理。

C语言提供了一系列丰富的运算符,包括算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符以及杂七杂八的运算符等,下面会详细介绍。

算术运算符

算术运算符用于执行基本的数学运算,包括加法、减法、乘法、除法等。C语言支持的算术运算符如下表所示:

运算符描述示例
+加法a + b
-减法a - b
*乘法a * b
/除法,结果为浮点数(如果操作数中有浮点数)或整数a / b, 10.0 / 3.0
%取模(求余数)a % b
++自增,前置或后置++a 或 a++
--自减,前置或后置--a 或 a--

示例代码

#include <stdio.h>

int main() {
    int a = 10, b = 3;
    float c = 5.5, d = 2.0;

    printf("a + b = %d\n", a + b);
    printf("a - b = %d\n", a - b);
    printf("a * b = %d\n", a * b);
    printf("a / b = %d\n", a / b);  // 整数除法,结果为3
    printf("a %% b = %d\n", a % b); // 取模,结果为1
    printf("c / d = %.2f\n", c / d); // 浮点数除法,结果为2.75

    int x = 5;
    printf("前置自增: ++x = %d\n", ++x); // 先增后输出,结果为6
    printf("后置自增: x++ = %d\n", x++); // 先输出后增,结果为6,然后x变为7

    return 0;
}

扩展

  1. 整数除法和浮点数除法:在C语言中,当两个整数进行除法运算时,结果也是整数,小数部分会被舍弃。如果要得到浮点数结果,至少有一个操作数必须是浮点数。
  2. 自增和自减运算符:自增和自减运算符可以前置也可以后置。前置运算符会先改变变量的值,然后再使用改变后的值;而后置运算符会先使用变量的原始值,然后再改变变量的值。

关系运算符

关系运算符用于比较两个值,并返回一个布尔值(真或假)。C语言支持的关系运算符如下表所示:

运算符描述示例
==等于a == b
!=不等于a != b
>大于a > b
<小于a < b
>=大于或等于a >= b
<=小于或等于a <= b

示例代码

#include <stdio.h>

int main() {
    int a = 10, b = 20;

    if (a == b) {
        printf("a 等于 b\n");
    } else {
        printf("a 不等于 b\n");
    }

    if (a < b) {
        printf("a 小于 b\n");
    }

    if (a >= 15) {
        printf("a 大于或等于 15\n");
    }

    return 0;
}

扩展

  1. 关系运算符的返回值:关系运算符返回一个布尔值(在C语言中通常用整数1表示真,0表示假)。这些值常用于条件语句(如if语句)中。
  2. 链式比较:在C语言中,可以链式使用关系运算符进行比较,例如a < b < c。但这种用法并不推荐,代码的可读性太低。

逻辑运算符

逻辑运算符用于组合多个条件表达式,并返回一个布尔值。C语言支持的逻辑运算符如下表所示:

运算符描述示例
&&逻辑与,两个条件都为真时才为真a && b
||逻辑或,只要有一个条件为真就为真a || b
!逻辑非,取反!a

示例代码

#include <stdio.h>

int main() {
    int a = 10, b = 20, c = 15;

    if (a > 5 && b < 25) {
        printf("a 大于 5 且 b 小于 25\n");
    }

    if (a < 5 || b > 25) {
        printf("a 小于 5 或 b 大于 25\n");
    }

    if (!(a == b)) {
        printf("a 不等于 b\n");
    }

    return 0;
}

扩展

  1. 短路求值:逻辑与运算符&&和逻辑或运算符||具有短路求值的特性。即,如果第一个操作数已经能够确定整个表达式的结果,那么第二个操作数将不会被求值。这可以用于避免除零错误或访问空指针等潜在问题。

位运算符

位运算符用于对整数的二进制位进行操作。C语言支持的位运算符如下表所示:

运算符描述示例
&按位与,两个位都为1时才为1a & b
|按位或,只要有一个位为1就为1a | b
^按位异或,两个位不同时为1a ^ b
~按位取反,0变1,1变0~a
<<左移,将位向左移动指定的位数a << n
>>右移,将位向右移动指定的位数a >> n

示例代码

#include <stdio.h>

int main() {
    unsigned int a = 60; // 0011 1100
    unsigned int b = 13; // 0000 1101

    printf("a & b = %u\n", a & b); // 0000 1100 = 12
    printf("a \| b = %u\n", a | b); // 0011 1101 = 61
    printf("a ^ b = %u\n", a ^ b); // 0011 0001 = 49
    printf("~a = %u\n", ~a);       // 1100 0011 = 4294967275(32位无符号整数的补码)
    printf("a << 2 = %u\n", a << 2); // 1111 0000 = 240
    printf("a >> 2 = %u\n", a >> 2); // 0000 1111 = 15

    return 0;
}

扩展

  1. 位运算与掩码:位运算常用于与掩码(mask)结合使用,用来提取或设置特定位。例如,可以使用掩码0x0F(即二进制的00001111)来提取一个字节的低四位。
  2. 位运算的效率:位运算在处理大量数据时通常比普通的算术运算更高效,因为它们直接在二进制层面进行操作,避免了不必要的类型转换和计算。

赋值运算符

赋值运算符用于将值赋给变量。C语言支持的赋值运算符如下表所示:

运算符描述示例
=简单赋值a = b
+=加法赋值a += b
-=减法赋值a -= b
*=乘法赋值a *= b
/=除法赋值a /= b
%=取模赋值a %= b
<<=左移赋值a <<= n
>>=右移赋值a >>= n
&=按位与赋值a &= b
|=按位或赋值a |= b
^=按位异或赋值a ^= b

示例代码

#include <stdio.h>

int main() {
    int a = 10, b = 5;

    a += b; // a = a + b = 15
    printf("a += b = %d\n", a);

    a -= b; // a = a - b = 10
    printf("a -= b = %d\n", a);

    a *= b; // a = a * b = 50
    printf("a *= b = %d\n", a);

    a /= b; // a = a / b = 10
    printf("a /= b = %d\n", a);

    a %= b; // a = a % b = 0
    printf("a %= b = %d\n", a);

    a = 10;
    a <<= 2; // a = a << 2 = 40
    printf("a <<= 2 = %d\n", a);

    a >>= 2; // a = a >> 2 = 10
    printf("a >>= 2 = %d\n", a);

    a &= 3; // a = a & 3 = 2
    printf("a &= 3 = %d\n", a);

    a |= 5; // a = a | 5 = 7
    printf("a \|= 5 = %d\n", a);

    a ^= 3; // a = a ^ 3 = 4
    printf("a ^= 3 = %d\n", a);

    return 0;
}

扩展

  1. 赋值运算符的复合性:赋值运算符可以结合其他运算符使用,形成复合赋值运算符。这种写法既简洁又高效。
  2. 赋值运算的顺序:在C语言中,赋值运算是从右到左进行的。例如,在表达式a = b = c = 5;中,首先计算c = 5,然后将结果赋给b,最后将b的值赋给a

杂项运算符

除了上述几类运算符外,C语言还支持一些其他重要的运算符,包括sizeof运算符和三元运算符?:

sizeof运算符

sizeof运算符用于获取数据类型或变量在内存中占用的字节数。它的返回值是一个size_t类型的值。

示例代码

#include <stdio.h>

int main() {
    int a = 10;
    double b = 5.5;
    char c = 'A';

    printf("sizeof(int) = %lu\n", sizeof(int));
    printf("sizeof(double) = %lu\n", sizeof(double));
    printf("sizeof(char) = %lu\n", sizeof(char));
    printf("sizeof(a) = %lu\n", sizeof(a));
    printf("sizeof(b) = %lu\n", sizeof(b));
    printf("sizeof(c) = %lu\n", sizeof(c));

    return 0;
}

扩展

  • sizeof运算符在编译时计算,因此不会增加程序的运行时开销。
  • 对于指针类型,sizeof运算符返回的是指针本身的大小,而不是指针所指向的数据的大小。

三元运算符**?:**:

三元运算符是一种条件运算符,它根据一个布尔表达式的值来选择两个值中的一个。其语法为条件 ? 表达式1 : 表达式2

示例代码

#include <stdio.h>

int main() {
    int a = 10, b = 20;
    int max;

    max = (a > b) ? a : b;
    printf("max = %d\n", max);

    return 0;
}

扩展

  • 三元运算符常用于简化简单的条件判断语句,使代码更加简洁明了。
  • 三元运算符可以嵌套使用,但过多的嵌套会降低代码的可读性,应谨慎使用。

运算符优先级和结合性

运算符的优先级和结合性决定了在复杂表达式中各个运算符的执行顺序。C语言中的运算符优先级从高到低排列如下(部分运算符):

  1. () 圆括号
  2. ! 逻辑非
  3. */% 乘法、除法、取模
  4. +- 加法、减法
  5. <<>> 左移、右移
  6. <<=>>= 关系运算符
  7. ==!= 等于、不等于
  8. & 按位与
  9. ^ 按位异或
  10. | 按位或
  11. && 逻辑与
  12. || 逻辑或
  13. = 赋值运算符

示例代码

#include <stdio.h>

int main() {
    int a = 10, b = 20, c = 30;

    int result = a + b * c / (a + b); // 运算符优先级示例
    printf("result = %d\n", result); // 输出结果为 30

    return 0;
}

扩展

  • 圆括号()可以改变运算符的优先级和结合性,因此在使用复杂表达式时应合理使用圆括号来提高代码的可读性和准确性。
  • 运算符的结合性决定了相同优先级的运算符的执行顺序。例如,乘法运算符*和除法运算符/是左结合的,这意味着a * b / c等价于(a * b) / c