综合练习:猜数字小游戏
这是什么:猜数字小游戏 = 程序随机想一个 1~100 的数,你来猜,它提示"大了"还是"小了"。
为什么用:零件都齐了:变量记数据、流程做判断、函数搞封装、指针/引用改外部变量、类封装数据和行为。分章学是拼零件,这一章才把零件拧成一个能玩的成品。
如何用:照抄一段完整的 guess.cpp(提示函数 + while 循环 + cin/cout),g++ 编译运行。
::: tip 没有 C++ 环境? 打开 OnlineGDB,语言选 C++20,粘贴即玩。 :::
完整代码
#include <iostream>
#include <cstdlib> // rand、srand 住在这里
#include <ctime> // time 住在这里
using namespace std;
// 根据猜测给提示:返回 true 表示猜中了
bool giveHint(int guess, int secret) {
if (guess > secret) {
cout << "大了,再猜!" << endl;
return false;
}
if (guess < secret) {
cout << "小了,再猜!" << endl;
return false;
}
cout << "猜中了!答案就是 " << secret << endl;
return true;
}
int main() {
srand(static_cast<unsigned>(time(nullptr))); // 用当前时间打乱随机数
int secret = rand() % 100 + 1; // 1~100 的随机数
int count = 0;
cout << "我想好了一个 1~100 的数,猜猜看!" << endl;
while (true) {
int guess;
cout << "你猜: ";
cin >> guess; // 从键盘读入一个整数
count++;
if (giveHint(guess, secret)) {
break; // 猜中,游戏结束
}
}
cout << "一共猜了 " << count << " 次,厉害!" << endl;
return 0;
}
编译运行
保存为 guess.cpp,然后:
g++ guess.cpp -o guess
./guess
你会看到(一次真实对局示例,谜底随机,你的过程不会和我一样)
我想好了一个 1~100 的数,猜猜看!
你猜: 50
大了,再猜!
你猜: 25
小了,再猜!
你猜: 37
大了,再猜!
你猜: 31
猜中了!答案就是 31
一共猜了 4 次,厉害!
逐块解读
| 代码 | 作用 |
|---|---|
srand(time(nullptr)) |
用当前时间当"随机种子";不写它,每次运行谜底都一样 |
rand() % 100 + 1 |
随机数对 100 取余得 0~99,加 1 变 1~100(上一章的取余派上用场) |
cin >> guess |
cout 的兄弟:从键盘读入数据,对应 Python 的 input() |
while (true) |
不知道几次能猜中,就一直循环 |
if (giveHint(...)) break; |
提示函数返回 true(猜中)才离场 |
count++ |
每猜一次计一次数 |
用到的清单:函数(giveHint)、循环(while)、分支(if)、运算(%、++)、输入输出(cin/cout)——前七章的知识全在这 40 来行里。
彩蛋:和 Python 版比比行数
同样的游戏,Python 版约 25 行搞定;C++ 版要 40 行左右。多出来的行数去哪了?头文件、main 骨架、类型声明、分号——这些"仪式感"换来的是编译器全程把关和飞快运行。语言没有优劣,只有取舍。
进阶版:用引用修改外部变量
把 giveHint 改成用引用,直接修改外部的 count,不再在 main 里手动 count++:
// 进阶:引用传递 count,函数内部直接累加
bool giveHint(int guess, int secret, int& count) {
count++; // 直接修改外面的 count
if (guess > secret) {
cout << "大了,再猜!" << endl;
return false;
}
if (guess < secret) {
cout << "小了,再猜!" << endl;
return false;
}
cout << "猜中了!答案就是 " << secret << endl;
return true;
}
int main() {
// ... 前面相同 ...
while (true) {
int guess;
cout << "你猜: ";
cin >> guess;
if (giveHint(guess, secret, count)) { // 传入 count 的引用
break;
}
}
// ...
}
❓ 常见问题
Q1:rand() % 100 + 1 为什么能得到 1~100?
rand() 返回 0 到某个最大值(通常 32767)的整数。% 100 得到 0~99,再 + 1 就变成 1~100。
Q2:为什么要 srand(time(nullptr))?
不写 srand,程序每次运行都用同样的默认种子,rand() 产生的"随机"序列完全一样。用当前时间作为种子,每次运行谜底都不同。
Q3:cin >> guess 输入非数字会怎样?
如果用户输入字母,cin 会进入失败状态,后续读入都失效。入门阶段不处理也可以;进阶后可用 cin.clear() 和 cin.ignore() 恢复。
⚠️ 新手翻车现场
翻车一:每次运行谜底都一样
// 错误:漏了 srand
int secret = rand() % 100 + 1;
问题:没有设置随机种子,rand() 每次都用默认种子,产生相同序列。
修正:在 rand() 之前加 srand(static_cast<unsigned>(time(nullptr)));。
翻车二:cin 读入后下一次循环不等待输入
这通常是因为之前的 cin 读入失败(比如输入了字母),导致 cin 进入错误状态,后续读入都被跳过。
修正:入门阶段保证只输入整数即可;进阶可加 if (!(cin >> guess)) { cin.clear(); cin.ignore(10000, '\n'); continue; }。
🎯 什么时候用这套知识
- 做小型命令行交互程序(猜数字、计算器、单位换算)
- 理解"随机数需要种子""用 cin/cout 做交互"
- 作为 C++ 基础的结业项目,验证前七章是否都掌握了
📝 本章小结
srand定种子,rand出随机数,cin收答案,break收官rand() % N + 1得到 1~N 的随机整数while (true)配合break实现"未知次数循环"- 函数封装提示逻辑,主循环只负责读入和判断
- 引用版
giveHint展示了如何让函数修改外部变量 - 记忆口诀:srand 定种子,rand 出随机,cin 收答案,break 收官游戏。
动手改
- 把范围改成 1~200(只动
rand() % 100 + 1那一行) - 猜中后追问"再来一局吗(y/n)",输入 y 就重开一局(提示:外层再套一个循环)
- 进阶:最多只许猜 7 次,超了宣布"游戏失败"并公布答案——想想为什么 7 次一定够猜中 1~100?
- 尝试用
switch替换giveHint里的if/else,看看代码是否更清晰(提示:switch不适合区间比较,这里可能不太合适,亲自试过再下结论)
C++ 基础毕业 🎉 下一站 STL,站在巨人的肩膀上写代码