第 8 章 M1 综合实战——从零到你的第一个计算器
🏗️ 前情回顾:第 1~7 章知识点散落一地——变量、类型、输入输出、运算、数学函数。现在把它们串成一条项链,从零写出一个能用的计算器。
🎯 本章目标
学完这一章,你能:
- 把变量、类型、输入输出、运算符组合成一个完整程序
- 理解"输入 → 处理 → 输出"这个 IPO 模型
- 独立写出一个能加减乘除的计算器
- 学会处理"除数为 0"这种异常情况
- 写出结构清晰、有注释、有缩进的好代码
📖 故事引入
小明学编程刚满一个月。有一天他妈妈问他:"你学了这么久编程,能做个什么东西出来?"
小明愣了一下。他会写 int a = 5;,会用 cin >> x;,会算 a + b……但这些东西好像都是"零件",从来没有组装成一个完整的"机器"。
他决定做一个计算器——妈妈输入两个数字和一个运算符,程序自动算出结果。这个想法简单,但能用的计算器要串起 M1 所有知识:变量存数字,cin 接收输入,运算符判断做哪种运算,cout 输出结果。
一个小时后,小明把笔记本电脑抱到妈妈面前:"妈,试试我的计算器。"
妈妈输入"15 / 0",程序没有崩溃,而是优雅地提示:"除数不能为 0!"
妈妈惊讶地看了小明一眼:"你还知道考虑这个?"
小明笑了——这就是编程教会他的第一件事:写程序不只是让功能跑起来,还要考虑它会遇到的所有可能。
🧱 知识讲解
8.1 程序的骨架:IPO 模型
所有程序——不管多复杂——本质上都遵循一个三步骤模式:
输入(Input) → 处理(Process) → 输出(Output)你用过计算器 APP 吧?你按数字和运算符(输入),它内部运算(处理),屏幕上显示出结果(输出)。这就是 IPO。
我们写计算器,也按这个骨架搭:
I:cin 接收两个数 + 一个运算符
P:根据运算符,做对应的计算
O:cout 输出结果先把骨架画清楚,再往里面填肉。这比一上来就埋头敲代码高效十倍。
8.2 用选择结构判断运算符
用户可能输入 +、-、*、/ 四种运算符中的一种。怎么让程序"知道"该做哪种运算?
if (op == '+') {
result = a + b;
} else if (op == '-') {
result = a - b;
} else if (op == '*') {
result = a * b;
} else if (op == '/') {
result = a / b;
} else {
cout << "不支持的运算符!" << endl;
return 1; // 异常退出
}注意运算符用 char 类型存储——一个字符变量,刚好装一个 '+' 或 '*'。
8.3 守护除法:除数为 0 怎么办?
这是计算器里最容易被攻击的 bug。15 ÷ 0 在数学上没有意义,在 C++ 里会导致程序崩溃(浮点除法得到 inf,整数除法直接炸)。
写除法之前,加一堵"防火墙":
if (op == '/') {
if (b == 0) {
cout << "错误:除数不能为 0!" << endl;
} else {
result = a / b;
}
}这叫做防御性编程——假设用户会犯所有可能的错,提前挡住。养成这个习惯,你的代码质量就能甩开 80% 的初学者。
8.4 完整代码:迷你计算器
先看一个"典型初学者版本"——你能找出几个问题?
// ❌ 错误版:隐患重重
#include <iostream>
using namespace std;
int main() {
int a, b, result; // 用 int → 不支持小数
char op;
cin >> a >> op >> b;
if (op == '+') result = a + b;
if (op == '-') result = a - b;
if (op == '*') result = a * b;
if (op == '/') result = a / b; // 没检查除数为 0!
cout << result << endl;
return 0;
}问题清单:① int 不支持小数 ② 除法没检查除数 ③ 没有处理非法运算符 ④ 用多个 if 而不是 else if(效率低)
✅ 把前面的零件组装起来——正确的版本:
#include <iostream>
using namespace std;
int main() {
double a, b, result; // 用 double 支持小数
char op; // 用 char 存运算符
cout << "=== 迷你计算器 ===" << endl;
cout << "请输入算式(如 5 + 3):" << endl;
cin >> a >> op >> b; // 一次读三个:数 运算符 数
// 根据运算符选择计算方式
if (op == '+') {
result = a + b;
} else if (op == '-') {
result = a - b;
} else if (op == '*') {
result = a * b;
} else if (op == '/') {
if (b == 0) {
cout << "错误:除数不能为 0!" << endl;
return 1;
}
result = a / b;
} else {
cout << "错误:不支持的运算符 " << op << endl;
return 1;
}
cout << a << " " << op << " " << b << " = " << result << endl;
return 0;
}💡
cin >> a >> op >> b;一行读三个值——程序会智能地跳过空格,把数字读给a,把字符读给op,把下一段数字读给b。这就是 C++ 输入流的便利之处。
8.5 好代码的三个习惯
写完程序不是终点,"写得好"才是。从你的第一个完整程序开始,养成三个习惯:
① 有意义的变量名
❌ double a, b, c; — 一个月后自己都看不懂 ✅ double num1, num2, result; — 一眼就知道是干嘛的
② 适当的注释
不是每行都写注释,而是在关键位置写:
// 除法需检查除数不为 0
if (b == 0) { ... }③ 一致的缩进
每一层 {} 缩进 2 或 4 格,让代码像目录树一样层次分明。大多数 IDE 按一下 Tab 键自动缩进——养成敲 { 就顺手缩进的习惯。
✋ 动手试试
试试 1:把上面的完整代码敲进你的 IDE,运行三遍,分别测试:
10 + 3(正常加法)7 / 0(除零检测)9 ^ 2(非法运算符)
观察输出分别是什么。
试试 2:把 double 全部换成 int,再测试 7 / 2——结果是多少?为什么会这样?(回忆第 6 章的整数除法规则。)
试试 3:你的计算器现在只支持两个数。试着扩展成支持三个数相加:用户输入 5 + 3 + 2,程序输出 10。(提示:多声明一个变量 c,在 if 里多加一条计算。)
⚠️ 你踩过这些坑吗
- [ ] 坑 1:整数除法导致结果错误 — 用
int存操作数,输入7 / 2→ 输出3。优先用double,除非你确定用户只需要整数。 - [ ] 坑 2:
op用string存 —string op;然后比较if (op == "+")——能跑,但小题大做。单个字符用char。 - [ ] 坑 3:忘了检查除数 —
result = a / b;当b = 0时程序崩溃。除法前先if (b == 0)检查。 - [ ] 坑 4:
cin >> a >> op >> b输入时空格不对 — 用户输入5+3(没空格)也能正确解析,但建议加空格更清晰。
📝 练习
基础题
1. 填空题:IPO 模型中,I 代表 ____,P 代表 ____,O 代表 ____。
2. 选择题:用户输入 8 / 0,如果程序没有检查除数,会发生什么? A. 自动输出 0 B. 程序崩溃或输出异常值 C. 输出 8 D. 自动退出
3. 读代码:以下程序输入 10 + 5 后输出什么?
int a, b;
char op;
cin >> a >> op >> b;
if (op == '+') cout << a + b;
else if (op == '-') cout << a - b;4. 判断题
(1)程序里的除数为 0 只会让结果变成 0,不会崩溃。( ) (2)char 是存单个字符的类型,适合存运算符。( ) (3)IPO 模型只适用于计算器程序。( ) (4)cin >> a >> op >> b; 可以一次性读取数字和字符。( )
提高题
5. 编程题 — 升级计算器
在迷你计算器的基础上增加"取模运算"(%)。用户输入 17 % 5,程序输出 2。注意:取模运算也需检查除数是否为 0,且操作数必须是整数(提示:用 long long 存)。
6. 编程题 — 算式智能识别
用户输入一个完整的算式字符串,如 "15+23"(不带空格),程序自动解析出两个操作数和运算符并计算结果。提示:遍历字符串找到运算符位置,再用 substr 拆分。
7. 分析题
下面这段代码在用户输入 10 / 0 时会发生什么?如果输入 10 % 0 呢?
#include <iostream>
using namespace std;
int main() {
int a, b; char op;
cin >> a >> op >> b;
if (op == '/') cout << a / b;
if (op == '%') cout << a % b;
return 0;
}请指出问题并写出修改方案。
挑战题
8. 编程题 — 多步运算
让用户输入一个三步算式(如 3 + 5 * 2),程序按正确优先级计算。这题需要你提前预习下一模块的"分支判断"——怎么区分 + 和 * 的优先级?试着用 if 先判断运算符中的 * 和 /,再判断 + 和 -。
9. 设计题
回顾 M1 全部 8 章,画一张"知识地图":每一章的关键知识点用一句话总结,并用箭头标出章节之间的依赖关系(哪一章是后面章节的基础)。完成后和同桌交换对比,看看谁的地图更清晰。
🧠 本章小结
M1 知识串烧 —— 你的第一个计算器:
【IPO 骨架】
Input: cin >> a >> op >> b
Process: if-else 根据 op 选择运算
Output: cout << result
【知识点回顾】
变量声明 → double a, b, result; char op;
cin/cout → 输入算式,输出结果
运算符 → + - * / 算术运算
类型选择 → double(支持小数),int(整数模式)
防御性编程 → 除数为 0 必须检查
【好代码习惯】
有意义的变量名 | 关键位置加注释 | 一致缩进📝 配套练习
共8题。M1收官。每题都不只考一个知识点——时间换算考取模+整除,苹果采购考多变量+算术,三角形面积考cmath+格式。学生做完这8题,M1所有技能应该能独立调用。。★核心(课堂必做) ◆拓展(课后练习) ★★★挑战(选做)
| 级别 | 题号 | 链接 | 覆盖知识点 |
|---|---|---|---|
| ★ 核心 | J0011 | https://hydro.ac/d/srqc/p/J0011 | double、pow、printf、全章串联 |
| ◆ 拓展 | J0020 | https://hydro.ac/d/srqc/p/J0020 | 时间换算、取模+整除、速度计算 |
| ◆ 拓展 | J0021 | https://hydro.ac/d/srqc/p/J0021 | int、百分比、类型选择的"读题决策" |
| ◆ 拓展 | J0015 | https://hydro.ac/d/srqc/p/J0015 | 算术、预测模型、变量关系 |
| ◆ 拓展 | J0016 | https://hydro.ac/d/srqc/p/J0016 | 多变量、批量采购、算术综合 |
| ◆ 拓展 | J0024 | https://hydro.ac/d/srqc/p/J0024 | 整除/取模、余数处理、现实建模 |
| ◆ 拓展 | J0025 | https://hydro.ac/d/srqc/p/J0025 | 余数、边界情况、苹果虫子问题 |
| ★★★ 挑战 | J0023 | https://hydro.ac/d/srqc/p/J0023 | 三角形面积、sqrt、格式输出、综合检验 |
| ◆ 拓展 | luogu-P1425 | https://hydro.ac/p/luogu-P1425 | 时间计算、取模、格式化输出 |
| ◆ 拓展 | luogu-P1421 | https://hydro.ac/p/luogu-P1421 | 整除/取模、算术综合 |
| ◆ 拓展 | luogu-P1150 | https://hydro.ac/p/luogu-P1150 | while、减法模拟、计数器 |
| ◆ 拓展 | luogu-P1887 | https://hydro.ac/p/luogu-P1887 | 算术、最值、贪心启蒙 |
| ◆ 拓展 | luogu-P2705 | https://hydro.ac/p/luogu-P2705 | 组合思维、算术 |
💡 练习建议:先完成 2 道★核心题,确保掌握本章基本方法;再完成 11 道◆拓展题,覆盖不同变式和细节;★★★挑战题建议在完成拓展题后再做,涉及多知识点综合。
配套练习
共8题。M1收官。每题都不只考一个知识点——时间换算考取模+整除,苹果采购考多变量+算术,三角形面积考cmath+格式。学生做完这8题,M1所有技能应该能独立调用。。★核心(课堂必做) · ◆拓展(课后练习) · ★★★挑战(选做)
| 级别 | 题号 | 链接 | 覆盖知识点 |
|---|---|---|---|
| ★ 核心 | J0011 | https://hydro.ac/d/srqc/p/J0011 | double、pow、printf、全章串联 |
| ◆ 拓展 | J0020 | https://hydro.ac/d/srqc/p/J0020 | 时间换算、取模+整除、速度计算 |
| ◆ 拓展 | J0021 | https://hydro.ac/d/srqc/p/J0021 | int、百分比、类型选择的"读题决策" |
| ◆ 拓展 | J0015 | https://hydro.ac/d/srqc/p/J0015 | 算术、预测模型、变量关系 |
| ◆ 拓展 | J0016 | https://hydro.ac/d/srqc/p/J0016 | 多变量、批量采购、算术综合 |
| ◆ 拓展 | J0024 | https://hydro.ac/d/srqc/p/J0024 | 整除/取模、余数处理、现实建模 |
| ◆ 拓展 | J0025 | https://hydro.ac/d/srqc/p/J0025 | 余数、边界情况、苹果虫子问题 |
| ★★★ 挑战 | J0023 | https://hydro.ac/d/srqc/p/J0023 | 三角形面积、sqrt、格式输出、综合检验 |
| ◆ 拓展 | luogu-P1425 | https://hydro.ac/p/luogu-P1425 | 时间计算、取模、格式化输出 |
| ◆ 拓展 | luogu-P1421 | https://hydro.ac/p/luogu-P1421 | 整除/取模、算术综合 |
| ◆ 拓展 | luogu-P1150 | https://hydro.ac/p/luogu-P1150 | while、减法模拟、计数器 |
| ◆ 拓展 | luogu-P1887 | https://hydro.ac/p/luogu-P1887 | 算术、最值、贪心启蒙 |
| ◆ 拓展 | luogu-P2705 | https://hydro.ac/p/luogu-P2705 | 组合思维、算术 |
练习建议:先在课堂完成 1 道★核心题,掌握本章基本方法;课后完成 11 道◆拓展题,覆盖不同变式和细节;★★★挑战题建议在完成拓展题后再做,涉及多知识点综合。
自查清单:
- [ ] 我能画出 IPO 模型图
- [ ] 我能独立写出迷你计算器的完整代码
- [ ] 我知道除法前必须检查除数是否为 0
- [ ] 我知道
char和string的区别,单个字符用char - [ ] 我的代码有缩进、有注释、变量名有意义
- [ ] 我知道 M1 八个章节分别讲了什么
🚀 下章预告
你的计算器还很"傻"——每次运行只能算一道题,算完就退出。如果想连续计算多道题,需要一遍遍重新运行程序。有没有办法让程序自己循环起来,算完一道再接下一道?
下一模块 M2,我们将解锁程序的"判断力"——if、else、switch,让你的程序不再是流水线上的机器,而是一个会做选择、能根据不同情况走不同岔路的智能体。