C语言运算符与表达式

运算符是用于执行各种操作的符号,如加法、比较、逻辑判断等;表达式是由运算符和操作数组成的式子,每个表达式都有一个确定的值。 掌握C语言的运算符及其优先级、结合性,是编写正确程序的基础。本章将系统介绍C语言中所有运算符及其用法。

📚 运算符分类总览

C语言提供丰富的运算符,根据功能可分为以下几类:

  • 算术运算符
  • 关系运算符
  • 逻辑运算符
  • 位运算符
  • 赋值运算符
  • 条件运算符(三目运算符)
  • 逗号运算符
  • sizeof运算符
  • 指针运算符(& 和 *)
  • 其他(下标、函数调用等)

➕ 算术运算符

算术运算符用于执行基本的数学运算。

运算符名称示例说明
+加法a + b求两个数之和
-减法a - b求两个数之差
*乘法a * b求两个数之积
/除法a / b两个数相除。如果操作数都是整数,结果为整数(截断)
%取模(求余)a % b求整除后的余数,操作数必须为整数
++自增a++++a变量增加1
--自减a----a变量减少1

📝 示例代码

#include <stdio.h>

int main() {
    int a = 10, b = 3;
    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

    // 自增自减
    int x = 5;
    printf("x++ = %d\n", x++);  // 先使用x(5),再自增
    printf("现在 x = %d\n", x);
    printf("++x = %d\n", ++x);  // 先自增,再使用(x为7)
    return 0;
}
注意: 自增/自减运算符只能用于变量,不能用于常量或表达式,如 ++(a+b) 是错误的。

⚖️ 关系运算符

关系运算符用于比较两个值的大小关系,返回结果为1(真)或0(假)。

运算符名称示例说明
==等于a == b判断a是否等于b
!=不等于a != b判断a是否不等于b
>大于a > b判断a是否大于b
<小于a < b判断a是否小于b
>=大于等于a >= b判断a是否大于等于b
<=小于等于a <= b判断a是否小于等于b

🔍 逻辑运算符

逻辑运算符用于组合多个条件,结果也为真(1)或假(0)。

运算符名称示例说明
&&逻辑与a && b两者都为真时结果为真
||逻辑或a || b至少一个为真时结果为真
!逻辑非!a将真变假,假变真

📝 示例代码

#include <stdio.h>

int main() {
    int a = 5, b = 3, c = 8;
    printf("a > b && a < c: %d\n", (a > b) && (a < c));  // 1 (真)
    printf("a > b || a > c: %d\n", (a > b) || (a > c));  // 1 (真)
    printf("!(a > b): %d\n", !(a > b));                  // 0 (假)

    // 短路求值示例
    int x = 0;
    if (x && (++x > 0)) {   // 因为x为0,左边为假,右边表达式不会执行
        // 不会进入
    }
    printf("x = %d\n", x);  // 输出0,证明++x未执行
    return 0;
}
短路求值: 逻辑与 && 和逻辑或 || 采用短路求值策略,即当左侧表达式已能确定最终结果时,右侧表达式不再计算。

⚡ 位运算符

位运算符直接对整数的二进制位进行操作,是C语言底层操作的重要特性。

运算符名称示例说明
&按位与a & b对应位都为1时结果为1
|按位或a | b对应位至少一个为1时结果为1
^按位异或a ^ b对应位不同时结果为1
~按位取反~a将每一位取反
<<左移a << n将二进制位左移n位,低位补0
>>右移a >> n将二进制位右移n位,无符号数高位补0,有符号数依编译器而定
#include <stdio.h>

int main() {
    unsigned char a = 0b10101100;  // 172
    unsigned char b = 0b01101101;  // 109

    printf("a & b = %u\n", a & b);   // 00101100 = 44
    printf("a | b = %u\n", a | b);   // 11101101 = 237
    printf("a ^ b = %u\n", a ^ b);   // 11000001 = 193
    printf("~a = %u\n", (unsigned char)~a);  // 01010011 = 83

    unsigned char c = 0b00001010;   // 10
    printf("c << 2 = %u\n", c << 2); // 00101000 = 40
    printf("c >> 1 = %u\n", c >> 1); // 00000101 = 5
    return 0;
}

📝 赋值运算符

赋值运算符用于将右侧表达式的值赋给左侧变量。除了基本赋值=,C语言还提供复合赋值运算符。

运算符示例等价于
=a = b将b的值赋给a
+=a += ba = a + b
-=a -= ba = a - b
*=a *= ba = a * b
/=a /= ba = a / b
%=a %= ba = a % b
&=a &= ba = a & b
|=a |= ba = a | b
^=a ^= ba = a ^ b
<<=a <<= na = a << n
>>=a >>= na = a >> n

❓ 条件运算符(三目运算符)

格式:表达式1 ? 表达式2 : 表达式3
如果表达式1为真,则整个表达式的值为表达式2的值,否则为表达式3的值。

#include <stdio.h>

int main() {
    int a = 10, b = 20;
    int max = (a > b) ? a : b;   // max = 20
    printf("较大值为: %d\n", max);

    // 可以嵌套使用
    int x = 5, y = 8, z = 3;
    int max3 = (x > y) ? ((x > z) ? x : z) : ((y > z) ? y : z);
    printf("三个数中的最大值: %d\n", max3);
    return 0;
}

📌 逗号运算符

逗号运算符,用于将多个表达式组合成一个表达式,整个表达式的值为最后一个表达式的值。

#include <stdio.h>

int main() {
    int a, b;
    a = (b = 3, b + 2);   // 先计算b=3,再计算b+2=5,然后将5赋给a
    printf("a = %d, b = %d\n", a, b);  // a=5, b=3

    // 常用于循环中
    for (int i = 0, j = 10; i < j; i++, j--) {
        printf("i=%d, j=%d\n", i, j);
    }
    return 0;
}

📏 sizeof运算符

sizeof是一个单目运算符,用于计算数据类型或变量所占内存的字节数,结果类型为size_t

#include <stdio.h>

int main() {
    int a;
    printf("Size of int: %zu\n", sizeof(int));
    printf("Size of a: %zu\n", sizeof a);     // 括号可省略
    printf("Size of double: %zu\n", sizeof(double));
    printf("Size of array: %zu\n", sizeof(int[10]));  // 计算类型长度
    return 0;
}

📊 运算符优先级与结合性

当一个表达式中包含多个运算符时,优先级决定运算顺序,结合性决定相同优先级的运算符是从左向右还是从右向左计算。

优先级运算符结合性
1(最高)() [] . ->从左到右
2++ -- ! ~ + - * & (类型) sizeof(单目)从右到左
3* / %从左到右
4+ -从左到右
5<< >>从左到右
6< <= > >=从左到右
7== !=从左到右
8&从左到右
9^从左到右
10|从左到右
11&&从左到右
12||从左到右
13?:从右到左
14= += -= *= /= %= &= ^= |= <<= >>=从右到左
15(最低),从左到右
建议: 对于复杂的表达式,使用括号()明确运算顺序,可以提高代码可读性,避免歧义。

🔄 类型转换

在表达式中,不同类型的操作数会进行类型转换,以保证运算的合法性。

  • 隐式转换(自动类型提升):较小的整数类型(char, short)在表达式中会自动转换为int;不同类型的混合运算中,较低精度会向较高精度转换(如int → long → unsigned long → float → double)。
  • 显式转换(强制类型转换):使用(类型)表达式强制转换,如(float)a / b
#include <stdio.h>

int main() {
    int a = 10;
    float b = 3.14;
    double c = 2.718;

    // 隐式转换:a 转换为 float 与 b 运算,结果转为 double 再与 c 运算
    double result = a + b + c;

    // 强制转换:避免整数除法
    int x = 5, y = 2;
    float ratio = (float)x / y;   // 2.5 而不是 2
    printf("ratio = %f\n", ratio);

    return 0;
}

运算符与表达式是C语言的核心组成部分。熟练运用各类运算符并理解优先级、结合性,能让你写出更简洁、高效的代码。 下一章将学习流程控制语句(if、switch、循环等),开始构建程序的逻辑结构。