C: 运算符与表达式

运算符就像厨房里的工具——切菜用刀,炒菜用锅,不同的食材需要不同的工具,不同的计算也需要不同的运算符。

1. 算术运算符

C语言提供了7个基本算术运算符,用来完成最常见的数学计算。

运算符 含义 示例 结果
+ 加法 5 + 3 8
- 减法 5 - 3 2
* 乘法 5 * 3 15
/ 除法 7 / 2 3
% 取余 7 % 2 1
+ 正号 +5 5
- 负号 -5 -5

(1) 整数除法的陷阱

两个整数相除,结果还是整数,小数部分直接丢弃,不是四舍五入。

C
#include <stdio.h>

int main(void) {
    int a = 7;
    int b = 2;
    printf("%d / %d = %d\n", a, b, a / b);
    printf("%d %% %d = %d\n", a, b, a % b);
    return 0;
}
TEXT 📖 仅展示
7 / 2 = 3
7 % 2 = 1
💡 想得到带小数的结果,至少让一个操作数是浮点数:7.0 / 2 结果是 3.5

(2) 取余运算的用途

取余运算 % 只能用于整数,它有几个非常实用的场景:

C
#include <stdio.h>

int main(void) {
    int n = 12345;
    printf("个位数: %d\n", n % 10);
    printf("是否偶数: %s\n", n % 2 == 0 ? "是" : "否");
    return 0;
}
TEXT 📖 仅展示
个位数: 5
是否偶数: 否

2. 自增与自减运算符

自增 ++ 让变量加1,自减 -- 让变量减1。它们各有两种写法:前置和后置,区别在于表达式的返回值不同。

(1) 前置与后置的区别

写法 名称 效果 表达式的值
++i 前置自增 i先加1 加1后的新值
i++ 后置自增 i先加1 加1前的旧值
--i 前置自减 i先减1 减1后的新值
i-- 后置自减 i先减1 减1前的旧值
C
#include <stdio.h>

int main(void) {
    int a = 5;
    int b = ++a;
    printf("前置: a=%d, b=%d\n", a, b);

    int c = 5;
    int d = c++;
    printf("后置: c=%d, d=%d\n", c, d);
    return 0;
}
TEXT 📖 仅展示
前置: a=6, b=6
后置: c=6, d=5
⚠️ 不要在同一个表达式中对同一个变量多次使用自增自减,如 a = ++a + a++,行为未定义,不同编译器结果不同。


3. 关系运算符

关系运算符用来比较两个值,结果是"真"(1) 或"假"(0)。

运算符 含义 示例 结果
== 等于 5 == 5 1
!= 不等于 5 != 3 1
< 小于 3 < 5 1
> 大于 3 > 5 0
<= 小于等于 5 <= 5 1
>= 大于等于 3 >= 5 0
C
#include <stdio.h>

int main(void) {
    int a = 10;
    int b = 20;
    printf("a == b: %d\n", a == b);
    printf("a != b: %d\n", a != b);
    printf("a < b:  %d\n", a < b);
    return 0;
}
TEXT 📖 仅展示
a == b: 0
a != b: 1
a < b:  1
⚠️ == 是比较,= 是赋值,写错会变成赋值且不会报错。建议把常量写在左边:5 == a,如果误写成 5 = a 编译器会报错。


4. 逻辑运算符

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

运算符 含义 示例 结果
&& 逻辑与 1 && 0 0
|| 逻辑或 1 || 0 1
! 逻辑非 !0 1

(1) 真值表

A B A && B A || B !A
0 0 0 0 1
0 1 0 1 1
1 0 0 1 0
1 1 1 1 0

(2) 短路求值

&& 如果左边为假,右边不再计算;|| 如果左边为真,右边不再计算。这个特性可以用来避免非法操作:

C
#include <stdio.h>

int main(void) {
    int divisor = 0;
    int value = 10;
    if (divisor != 0 && value / divisor > 5) {
        printf("条件成立\n");
    } else {
        printf("条件不成立,且没有除以零\n");
    }
    return 0;
}
TEXT 📖 仅展示
条件不成立,且没有除以零
💡 C语言中,0为假,任何非0值都为真(包括负数)。所以 -5 在逻辑判断中也是"真"。


5. 赋值运算符

基本赋值运算符 = 把右边的值存入左边的变量。C还提供了复合赋值运算符,把运算和赋值合二为一。

复合赋值 等价写法
a += b a = a + b
a -= b a = a - b
a *= b a = a * b
a /= b a = a / b
a %= b a = a % b
C
#include <stdio.h>

int main(void) {
    int score = 80;
    score += 10;
    printf("加分后: %d\n", score);
    score -= 25;
    printf("扣分后: %d\n", score);
    score *= 2;
    printf("翻倍后: %d\n", score);
    return 0;
}
TEXT 📖 仅展示
加分后: 90
扣分后: 65
翻倍后: 130

6. 条件运算符(三目运算符)

条件运算符 ?: 是C语言中唯一的三目运算符,语法为:

C
条件 ? 表达式1 : 表达式2

条件为真执行表达式1,否则执行表达式2。它是 if-else 的简写形式。

C
#include <stdio.h>

int main(void) {
    int age = 20;
    char *status = age >= 18 ? "成年" : "未成年";
    printf("年龄%d,%s\n", age, status);

    int a = 15, b = 28;
    int max = a > b ? a : b;
    printf("较大值: %d\n", max);
    return 0;
}
TEXT 📖 仅展示
年龄20,成年
较大值: 28

7. 逗号运算符

逗号运算符 , 从左到右依次执行每个表达式,整个逗号表达式的值是最后一个表达式的值。

C
#include <stdio.h>

int main(void) {
    int a, b, c;
    c = (a = 1, b = 2, a + b);
    printf("a=%d, b=%d, c=%d\n", a, b, c);
    return 0;
}
TEXT 📖 仅展示
a=1, b=2, c=3
⚠️ 逗号运算符的优先级是所有运算符中最低的。注意区分"逗号运算符"和函数参数之间的逗号——后者不是逗号运算符。


8. sizeof 运算符

sizeof 用来获取数据类型或变量占用的内存字节数。它在编译时求值,不是运行时。

C
#include <stdio.h>

int main(void) {
    printf("char:   %zu 字节\n", sizeof(char));
    printf("int:    %zu 字节\n", sizeof(int));
    printf("float:  %zu 字节\n", sizeof(float));
    printf("double: %zu 字节\n", sizeof(double));

    int arr[5] = {1, 2, 3, 4, 5};
    printf("数组总大小: %zu 字节\n", sizeof(arr));
    printf("数组元素数: %zu\n", sizeof(arr) / sizeof(arr[0]));
    return 0;
}
TEXT 📖 仅展示
char:   1 字节
int:    4 字节
float:  4 字节
double: 8 字节
数组总大小: 20 字节
数组元素数: 5
💡 sizeof 对类型名要用括号(sizeof(int)),对变量可以不用括号(sizeof a),但为了统一风格,建议都加括号。


9. 运算符优先级

当一个表达式中有多个运算符时,优先级高的先计算。下表从高到低排列:

优先级 运算符 结合方向
1(最高) () [] -> . 左到右
2 ! ~ ++ -- +(正) -(负) *(解引用) &(取址) sizeof 右到左
3 * / % 左到右
4 + - 左到右
5 << >> 左到右
6 < <= > >= 左到右
7 == != 左到右
8 & 左到右
9 ^ 左到右
10 | 左到右
11 && 左到右
12 || 左到右
13 ?: 右到左
14 = += -= *= /= %= 右到左
15(最低) , 左到右
🔥 记不住优先级?不用死记——不确定时就加括号,括号永远最优先,而且让代码更清晰。

▶ 示例

综合运用各类运算符,计算一个三位数的各位数字之和:

C
#include <stdio.h>

int main(void) {
    int num = 952;
    int hundreds = num / 100;
    int tens = (num / 10) % 10;
    int ones = num % 10;
    int sum = hundreds + tens + ones;

    printf("数字: %d\n", num);
    printf("百位: %d, 十位: %d, 个位: %d\n", hundreds, tens, ones);
    printf("各位数字之和: %d\n", sum);
    return 0;
}
▶ 试一试
TEXT 📖 仅展示
数字: 952
百位: 9, 十位: 5, 个位: 2
各位数字之和: 16

▶ 示例

利用逻辑运算符和关系运算符,判断某年是否为闰年:

C
#include <stdio.h>

int main(void) {
    int year = 2024;
    int is_leap = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);

    printf("%d年%s闰年\n", year, is_leap ? "是" : "不是");
    return 0;
}
▶ 试一试
TEXT 📖 仅展示
2024年是闰年

10. 类型转换

(1) 隐式转换

当不同类型的数据参与运算时,编译器会自动将低精度类型转换为高精度类型:

C
#include <stdio.h>

int main(void) {
    int a = 5;
    double b = 2.0;
    double c = a / b;
    printf("5 / 2.0 = %f\n", c);

    char ch = 'A';
    int code = ch + 1;
    printf("'A' + 1 = %c (ASCII %d)\n", code, code);
    return 0;
}
TEXT 📖 仅展示
5 / 2.0 = 2.500000
'A' + 1 = B (ASCII 66)

转换方向:charintlongdoubleintunsignedlongdouble

(2) 强制转换

(类型名) 可以强制将一个值转为指定类型:

C
#include <stdio.h>

int main(void) {
    int a = 7, b = 2;
    double result = (double)a / b;
    printf("强制转换: %f\n", result);
    return 0;
}
TEXT 📖 仅展示
强制转换: 3.500000
⚠️ 强制转换不改变原变量的值和类型,它只是产生一个临时的新值。

❓ 常见问题

Q a++++a 在单独一行时有区别吗?
A 没有区别。只有在表达式中使用返回值时才不同,单独使用效果完全一样,但前置自增理论上级稍高。
Q === 到底怎么区分?
A = 是赋值("变成"),== 是比较("等于吗")。在if条件中误写成 if (a = 0) 不会报错但逻辑全错,建议常量写左边 if (0 == a)
Q 取余运算 % 能用于浮点数吗?
A 不能。% 只能用于整数类型。浮点数取余要用 fmod() 函数,需要 #include <math.h>
Q 运算符优先级需要全部背诵吗?
A 不需要。记住乘除模优先于加减、逻辑非优先于与优先于或就够了,其余情况加括号更安全。

📖 小节

📝 作业

  1. 编写程序,输入一个秒数(如3661),用 /% 计算出对应的小时、分钟和秒并输出。
  2. 编写程序,输入两个整数,用三目运算符找出较大值和较小值并输出。
  3. 编写程序,用 sizeof 输出你电脑上 shortintlonglong long 的大小,观察结果。
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏