运算符 — 加减乘除与比较
C语言学习教程
运算符 — 加减乘除与比较
🌟 课前故事:你是一个”数据加工厂”的厂长
假设你是一家果汁加工厂的厂长。每天早晨,工人把新鲜水果(数据)搬进工厂,你的机器(运算符)开始工作:清洗、榨汁、过滤、装瓶(处理数据),最后产出果汁成品(结果)。
在C语言里,运算符就是你的”加工机器”:
- 你有把数据加在一起的”加法机”
- 有比较大小的”比较仪”
- 有判断真假的”逻辑门”
数据(变量)是原材料,运算符是加工工具,结果就是产出。今天,我们来清点你的”工厂设备”,学习每一种运算符的用法。
📖 概念讲解:运算符是什么?
什么是运算符?
运算符(Operator)是告诉计算机执行特定数学运算、逻辑运算或操作的特殊符号。运算符作用的对象叫操作数(Operand)。
操作数 运算符 操作数
↓ ↓ ↓
5 + 3 = 8
↑ ↑ ↑
左操作数 右操作数 结果
为什么需要运算符?
没有运算符,变量只是”存储盒”——数据躺在里面什么也做不了。有了运算符,程序才能:
- 计算数学结果
- 比较两个数的大小
- 判断条件是否成立
- 修改变量的值
C语言运算符家族(预览)
C语言的运算符非常丰富,今天重点学习最基本的五类:
┌──────────────────────────────────────────────┐
│ C语言运算符 │
│ │
│ 📐 算术运算符: + - * / % │
│ 📝 赋值运算符: = += -= *= /= │
│ 🔄 自增自减: ++ -- │
│ ⚖️ 比较运算符: == != > < >= <= │
│ 🧠 逻辑运算符: && || ! │
│ ... (还有更多,后面学) │
└──────────────────────────────────────────────┘
📐 第一部分:算术运算符
五种基本算术运算
| 运算符 | 名称 | 示例 | 结果 | 说明 |
|---|---|---|---|---|
+ | 加法 | 5 + 3 | 8 | 小学就会 |
- | 减法 | 5 - 3 | 2 | 小学就会 |
* | 乘法 | 5 * 3 | 15 | 注意:不是 ×! |
/ | 除法 | 5 / 2 | 2 | 整数除法会截断! |
% | 取余(模) | 5 % 2 | 1 | 5除以2的余数 |
基本算术示例
#include <stdio.h>
int main() {
int a = 10, b = 3;
printf("a = %d, b = %d\n\n", a, b);
printf("a + b = %d\n", a + b); // 10 + 3 = 13
printf("a - b = %d\n", a - b); // 10 - 3 = 7
printf("a * b = %d\n", a * b); // 10 * 3 = 30
printf("a / b = %d\n", a / b); // 10 / 3 = 3(注意!)
printf("a %% b = %d\n", a % b); // 10 % 3 = 1
return 0;
}
注意: printf 中输出百分号 % 本身,要用 %%。所以 %d 是格式占位符,而 %% 才输出一个 % 字符。
⚠️ 整数除法的”大坑”
C语言中,两个整数相除,结果还是整数——小数部分被直接丢弃,不是四舍五入!
int a = 5, b = 2;
// 整数除法
int result1 = a / b; // 5 / 2 = 2(不是2.5!)
float result2 = a / b; // 5 / 2 = 2.000000(还是2!)
// 为什么都等于2?
// 因为 a 和 b 都是整数,所以先做整数除法得到 2
// 然后才把 2 转成 float(2.0)赋值给 result2
// 小数部分在除法时就已经丢失了!
正确做法——至少让一个操作数是浮点数:
float result3 = 5.0 / 2; // 2.5 ✅ 5.0是浮点数
float result4 = 5 / 2.0; // 2.5 ✅ 2.0是浮点数
float result5 = 5.0 / 2.0; // 2.5 ✅ 两个都是浮点数
float result6 = (float)5 / 2; // 2.5 ✅ 强制转换5为浮点数
图解:整数除法 vs 浮点除法
整数除法: 5 / 2
┌──────────────────────┐
│ 2 ← 商(小数丢弃) │
│ ─── │
│ 2)5 │
│ 4 │
│ ─── │
│ 1 ← 余数(丢弃) │
└──────────────────────┘
结果 = 2
浮点除法: 5.0 / 2.0
┌──────────────────────┐
│ 2.5 ← 保留完整结果 │
│ ───── │
│ 2.0)5.0 │
│ 4.0 │
│ ──── │
│ 1.0 │
│ 1.0 │
│ ──── │
│ 0 │
└──────────────────────┘
结果 = 2.5
取余运算符 % 的妙用
取余是人类很早就掌握的运算——“10颗糖分给3个人,每人3颗,还剩1颗”。在编程中,取余有很多实用场景:
#include <stdio.h>
int main() {
// 1. 判断奇偶数
int num1 = 7, num2 = 8;
printf("%d 是%s\n", num1, num1 % 2 == 0 ? "偶数" : "奇数"); // 奇数
printf("%d 是%s\n", num2, num2 % 2 == 0 ? "偶数" : "奇数"); // 偶数
// 2. 取个位数
int n = 12345;
printf("个位:%d\n", n % 10); // 5
printf("十位:%d\n", (n / 10) % 10); // 4
printf("百位:%d\n", (n / 100) % 10);// 3
// 3. 循环周期(0~N-1的循环)
for (int i = 0; i < 10; i++) {
printf("%d ", i % 3); // 输出:0 1 2 0 1 2 0 1 2 0
}
printf("\n");
// 4. 判断闰年(能被4整除但不能被100整除,或能被400整除)
int year = 2024;
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
printf("%d 是闰年\n", year);
}
return 0;
}
重要限制: % 运算符的两个操作数必须是整数,不能用于浮点数!
// ❌ 错误
float x = 5.0 % 2.0; // error: invalid operands to binary %
// ✅ 正确
int x = 5 % 2; // 1
📝 第二部分:赋值运算符
基本赋值 =
int x;
x = 10; // 把 10 赋值给 x
x = x + 5; // 先算 x+5=15,再赋值给 x(x 变成 15)
重要理解: = 不是数学中的”等于”,而是赋值——把右边的值放入左边的变量。
复合赋值运算符(缩写)
| 写法 | 等价于 | 含义 |
|---|---|---|
x += 5 | x = x + 5 | x 增加 5 |
x -= 5 | x = x - 5 | x 减少 5 |
x *= 2 | x = x * 2 | x 翻倍 |
x /= 3 | x = x / 3 | x 变为原来的 1/3 |
x %= 3 | x = x % 3 | x 变为 x 除以 3 的余数 |
#include <stdio.h>
int main() {
int x = 10;
x += 5; printf("x += 5 → %d\n", x); // 15
x -= 3; printf("x -= 3 → %d\n", x); // 12
x *= 2; printf("x *= 2 → %d\n", x); // 24
x /= 5; printf("x /= 5 → %d\n", x); // 4
x %= 3; printf("x %%= 3 → %d\n", x); // 1
return 0;
}
为什么用复合赋值?
- 写起来更短
- 更清晰表达”在这个变量基础上修改”的意图
- 某些情况下效率更高(编译器优化)
🔄 第三部分:自增 ++ 和自减 --
加1和减1是最常见的操作之一,C语言为它们提供了专用运算符:
int i = 0;
i++; // 后置自增:i 加 1,返回加之前的值
++i; // 前置自增:i 加 1,返回加之后的值
i--; // 后置自减:i 减 1,返回减之前的值
--i; // 前置自减:i 减 1,返回减之后的值
前置 vs 后置:关键区别
#include <stdio.h>
int main() {
int a, b, x;
// === 后置自增:先用后加 ===
x = 5;
a = x++; // ① 先把 x 的值(5)赋给 a ② 然后 x 加 1 变成 6
printf("后置: a = %d, x = %d\n", a, x); // a=5, x=6
// === 前置自增:先加后用 ===
x = 5;
b = ++x; // ① 先让 x 加 1 变成 6 ② 然后把 x 的值(6)赋给 b
printf("前置: b = %d, x = %d\n", b, x); // b=6, x=6
return 0;
}
记忆口诀:
- 后置
x++:先用后加(“先”在前,“后”在后——按顺序读就是先用后加) - 前置
++x:先加后用(“先”在前,“后”在后——按顺序读就是先加后用)
图解:b = x++ vs b = ++x
x = 5 x = 5
b = x++; b = ++x;
步骤1: b = x (b=5) 步骤1: x = x+1 (x=6)
步骤2: x = x+1 (x=6) 步骤2: b = x (b=6)
结果: b=5, x=6 结果: b=6, x=6
↑ ↑ ↑ ↑
先 后 先 后
用 加 加 用
自增自减的典型使用场景
// 场景1:循环计数(最常用)
for (int i = 0; i < 10; i++) { // i++:每轮循环后+1
printf("%d ", i);
}
// 场景2:数组遍历
int arr[] = {1, 2, 3, 4, 5};
int idx = 0;
while (idx < 5) {
printf("%d ", arr[idx++]); // 先取arr[idx],然后idx+1
}
// 场景3:计数统计
int count = 0;
count++; // 找到一个,计数+1
count++; // 又找到一个,再+1
⚠️ 自增自减的陷阱
// ❌ 混乱代码(不要这样写!)
int x = 5;
int y = ++x + x++; // 结果不确定!不同编译器可能不同!
printf("%d\n", y);
// ❌ 多次修改同一个变量
int a = 1;
printf("%d %d %d\n", a++, a++, a++); // 结果不确定!
// ✅ 清晰代码
int x = 5;
x++; // x 现在是 6
int y = x; // y 也是 6
printf("%d\n", y);
原则: 一条语句中对同一个变量只使用一次自增/自减。让代码清晰比”炫技”重要100倍。
⚖️ 第四部分:比较运算符(关系运算符)
比较运算符用来比较两个值的大小关系,结果是一个”真假”值。
| 运算符 | 含义 | 示例 | 结果 |
|---|---|---|---|
== | 等于 | 5 == 3 | 0(假) |
!= | 不等于 | 5 != 3 | 1(真) |
> | 大于 | 5 > 3 | 1(真) |
< | 小于 | 5 < 3 | 0(假) |
>= | 大于等于 | 5 >= 5 | 1(真) |
<= | 小于等于 | 5 <= 3 | 0(假) |
在C语言中:
- 0 表示”假”(false)
- 非0(通常是1)表示”真”(true)
#include <stdio.h>
int main() {
int a = 10, b = 20;
printf("a = %d, b = %d\n\n", a, b);
printf("a == b : %d\n", a == b); // 0 (10不等于20)
printf("a != b : %d\n", a != b); // 1 (10确实不等于20)
printf("a > b : %d\n", a > b); // 0 (10不大于20)
printf("a < b : %d\n", a < b); // 1 (10小于20)
printf("a >= b : %d\n", a >= b); // 0 (10不大于等于20)
printf("a <= b : %d\n", a <= b); // 1 (10小于等于20)
return 0;
}
🔴 == 不是 =!这是新手最致命的错误!
// ❌ 经典错误
int x = 5;
if (x = 10) { // 注意:这是一个等号!
printf("永远会执行\n"); // 因为 x=10 是赋值,结果是10(非0=真)
}
// 这段代码不仅条件永远成立,还把 x 的值改成了 10!
// ✅ 正确写法
int x = 5;
if (x == 10) { // 两个等号才是比较!
printf("x 等于 10 时才会执行\n");
}
怎么记住? 一个等号 = 是赋值(把右边放入左边),两个等号 == 是比较(左边等于右边吗?)。
小技巧: 写比较时把常量放左边——if (10 == x)。如果误写成 if (10 = x),编译器会报错(因为不能给常量赋值),帮你”提前发现”!
比较运算符的使用场景
#include <stdio.h>
int main() {
int age = 20;
float score = 85.5f;
// 场景1:年龄判断
if (age >= 18) {
printf("已成年\n");
}
// 场景2:成绩判断
if (score >= 60.0f && score <= 100.0f) {
printf("成绩有效\n");
} else if (score < 0.0f || score > 100.0f) {
printf("成绩无效\n");
}
// 场景3:精确匹配
int answer = 42;
if (answer == 42) {
printf("答对了!\n");
}
// 场景4:范围判断
int year = 2024;
if (year >= 2000 && year <= 2099) {
printf("21世纪\n");
}
return 0;
}
🧠 第五部分:逻辑运算符
逻辑运算符用来组合多个条件,实现复杂的”与或非”逻辑。
| 运算符 | 名称 | 含义 | 真值表 |
|---|---|---|---|
&& | 逻辑与 (AND) | 两边都真才真 | T&&T=T, T&&F=F, F&&T=F, F&&F=F |
|| | 逻辑或 (OR) | 一边真就真 | T||T=T, T||F=T, F||T=T, F||F=F |
! | 逻辑非 (NOT) | 取反 | !T=F, !F=T |
逻辑与 && —— 全真才真
// 示例:判断一个数是否在 0~100 之间
int score = 85;
if (score >= 0 && score <= 100) {
printf("成绩有效\n");
}
// score >= 0 → 真(85 >= 0)
// score <= 100 → 真(85 <= 100)
// 真 && 真 → 真 ✓
&& 真值表
┌──────────────────┐
│ && │ 真 │ 假 │
├──────┼────┼─────┤
│ 真 │ 真 │ 假 │
│ 假 │ 假 │ 假 │
└──────────────────┘
记忆:&& 像一个严格的双重检查——
两个条件都通过才算通过
逻辑或 || —— 有真就真
// 示例:判断一个数是否在 0~100 范围之外
int score = -5;
if (score < 0 || score > 100) {
printf("成绩无效\n");
}
// score < 0 → 真(-5 < 0)
// score > 100 → 假(-5 > 100 不成立)
// 真 || 假 → 真 ✓
|| 真值表
┌──────────────────┐
│ || │ 真 │ 假 │
├──────┼────┼─────┤
│ 真 │ 真 │ 真 │
│ 假 │ 真 │ 假 │
└──────────────────┘
记忆:|| 像一个宽松的选择——
只要满足一个条件就通过
逻辑非 ! —— 颠倒黑白
int ready = 0; // 0 表示"假"(没准备好)
if (!ready) { // !0 = 真("没准备好"这个条件成立了)
printf("还没准备好\n");
}
int logged_in = 1; // 非0 表示"真"(已登录)
if (!logged_in) { // !1 = 假("未登录"这个条件不成立)
printf("请先登录\n"); // 这行不会执行
}
短路计算(重要概念)
&& 和 || 有一个重要的特性——短路计算:
// 短路与 (&&):如果左边是假,右边根本不会执行
int a = 5;
if (a > 10 && a++ == 6) {
printf("不会执行\n");
}
printf("a = %d\n", a); // a = 5(a++ 没有被执行!)
// 短路或 (||):如果左边是真,右边根本不会执行
int b = 15;
if (b > 10 || b++ == 16) {
printf("会执行\n");
}
printf("b = %d\n", b); // b = 15(b++ 没有被执行!)
短路计算的价值:
// 安全地检查:先确保分母不为0,再做除法
int x = 10, y = 0;
if (y != 0 && x / y > 5) { // 因为 y!=0 是假,x/y 根本不会计算,避免除以0崩溃
printf("比值大于5\n");
}
📊 运算符优先级
当多种运算符一起使用时,有严格的先后顺序:
优先级从高到低(同级从左到右):
() 圆括号(优先级最高,有括号先算括号)
↑
! ++ -- 逻辑非、自增、自减(从右到左)
↑
* / % 乘、除、取余
↑
+ - 加、减
↑
< > <= >= 比较运算符
↑
== != 等于、不等于
↑
&& 逻辑与
↑
|| 逻辑或
↑
= += -= 赋值(优先级最低,从右到左)
优先级示例
// 没有括号时
int result1 = 5 + 3 * 2; // 5 + (3*2) = 5 + 6 = 11
// 因为 * 优先级高于 +
int result2 = 10 - 4 / 2; // 10 - (4/2) = 10 - 2 = 8
// 因为 / 优先级高于 -
// 比较和算术混用时
int result3 = 5 + 3 > 7; // (5+3) > 7 = 8 > 7 = 1(真)
// 因为 + 优先级高于 >
// 逻辑和比较混用时
int result4 = 5 > 3 && 2 < 4; // (5>3) && (2<4) = 1 && 1 = 1(真)
// 因为 比较 优先级高于 &&
记不住优先级怎么办?——加括号!
// ❌ 让人困惑的代码
int result = a + b > c && d || e;
// ✅ 加括号后一目了然
int result = ((a + b) > c) && d || e;
// 🏆 最佳实践:不依赖优先级,用括号明确你的意图
int result = ((a + b) > c) && (d || e);
括号三原则:
- 不确定优先级时——加括号
- 优先级太多层时——加括号
- 想让别人一眼看懂时——加括号
多加括号不会影响程序性能,只会让代码更清晰。——编译器会帮你优化掉的。
⚠️ 常见错误(5个经典”坑”)
错误1:= 和 == 搞混(再强调一遍!)
// ❌ 错误代码
int score = 85;
if (score = 100) { // 赋值!score 被改成 100,条件恒为真
printf("满分!\n"); // 永远会输出
}
printf("%d\n", score); // 100(值被偷偷改了!)
// ✅ 正确代码
int score = 85;
if (score == 100) { // 比较!
printf("满分!\n"); // 只有真的是100分才输出
}
错误2:整数除法截断
// ❌ 错误代码
float result = 5 / 2; // result = 2.000000(小数部分丢了!)
printf("%f\n", result); // 用户困惑:为什么不是 2.5?
// ✅ 正确代码
float result = 5.0 / 2; // result = 2.500000
// 或者
float result = (float)5 / 2; // 强制转换
错误3:取余用错类型
// ❌ 错误代码
float x = 5.0f;
int r = x % 2; // 编译错误:% 不能用于浮点数
// ✅ 正确代码
int x = 5;
int r = x % 2; // ✅ 两个操作数都是整数
错误4:逻辑运算的括号遗漏
// ❌ 错误代码——意图:判断 x 在 10 到 20 之间
int x = 15;
if (10 < x < 20) { // 你以为在判断 10 < x < 20
printf("在范围内\n");
}
// 实际执行:(10 < x) < 20
// = (1) < 20 ← 因为 10<15 结果为真(1)
// = 1 ← 1<20 为真,所以恒为真!
// ✅ 正确代码
int x = 15;
if (x > 10 && x < 20) { // 分开写,用 && 连接
printf("在范围内\n");
}
错误5:混淆 & 和 &&(及 | 和 ||)
// & 和 | 是"位运算符"(对二进制位操作)——后面学
// && 和 || 是"逻辑运算符"(判断真假)
// ❌ 容易混淆
if (a > 5 & b < 10) // & 是位运算,虽然这里"碰巧也管用"但不是正确意图
if (a > 5 && b < 10) // && 才是逻辑与,表达"两个条件都满足"
// 初学者建议:始终用 && 和 || 做逻辑判断
💡 练习建议
初级练习
- 四则运算:输入两个整数,输出它们的和、差、积、商、余数
- 判断奇偶:输入一个整数,判断它是奇数还是偶数
- 成绩分级:输入成绩(0-100),判断是否及格(>=60)
中级练习
- 闰年判断:输入一个年份,判断是否是闰年
- 三位数拆分:输入一个三位数,分别输出百位、十位、个位数字
- 三角形判断:输入三个边长,判断能否构成三角形(任意两边之和大于第三边)
进阶思考
- 运算符优先级探索:不查表,猜猜
2 + 3 * 4 - 6 / 2的结果是多少,然后写代码验证 - 短路实验:设计实验验证
&&和||的短路行为 - 交换算法:不用第三个变量,交换两个 int 变量的值(提示:用加减法或异或)
📝 要点速查清单
-
+ - * / %五种算术运算:/整数除法截断,%只能用于整数 - 想要小数结果:至少一个操作数是浮点数(
5.0 / 2) -
+= -= *= /= %=复合赋值:x += 5等价于x = x + 5 -
++和--:前置先加后用,后置先用后加 -
==是比较(两个等号),=是赋值(一个等号)——绝对不混 -
!=不等于,>大于,<小于,>=大于等于,<=小于等于 -
&&逻辑与(全真才真),||逻辑或(有真就真),!逻辑非(颠倒真假) -
&&和||有短路特性:左边能决定结果时右边不执行 - 记不住优先级就加括号——
()优先级最高 - 不要写成
10 < x < 20,用x > 10 && x < 20代替
🔗 相关主题
- 上一课:变量与数据类型 — 运算符操作的”原材料”
- 继续学习:输入输出 — 让用户输入数据,用运算符处理
- 继续学习:条件判断 — 比较和逻辑运算符最常出现的地方
- 继续学习:位运算符 — 更底层的二进制位操作
- 参考:C语言运算符优先级完整表