🐸 青蛙编程网
首页 / C++ / C++ 基础 / 8. 综合练习

综合练习:猜数字小游戏

这是什么:猜数字小游戏 = 程序随机想一个 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. 把范围改成 1~200(只动 rand() % 100 + 1 那一行)
  2. 猜中后追问"再来一局吗(y/n)",输入 y 就重开一局(提示:外层再套一个循环)
  3. 进阶:最多只许猜 7 次,超了宣布"游戏失败"并公布答案——想想为什么 7 次一定够猜中 1~100?
  4. 尝试用 switch 替换 giveHint 里的 if/else,看看代码是否更清晰(提示:switch 不适合区间比较,这里可能不太合适,亲自试过再下结论)

C++ 基础毕业 🎉 下一站 STL,站在巨人的肩膀上写代码

📥 下载本章代码

ZIP 内含本章全部代码文件与说明,解压即用,与教程内容同步生成。