学习章节:分支和循环(下),练习 rand/srand/time 随机数 API,综合运用分支、循环、函数封装完成小游戏。
前言
学完 if‑else、switch、while、do‑while 分支循环语法之后,就可以写完整小项目了。猜数字游戏是非常经典的练手案例,把随机数、函数封装、循环菜单、条件判断全部结合在一起,锻炼对百行以内代码整体把控能力。
一、随机数相关函数知识点
1. rand()
int rand(void),生成伪随机数,范围 0 ~ RAND_MAX(一般 32767),头文件<stdlib.h>。
问题:直接调用 rand,每次运行程序得到的随机序列完全一样,因为默认种子固定为 1,属于伪随机。
2. srand()
void srand(unsigned int seed),设置随机数种子。程序运行期间只调用一次,种子变化,rand 输出序列才会变化。
3. time()
time_t time(time_t* timer),获取时间戳:1970‑01‑01 至今的秒数,头文件<time.h>。 传NULL只返回时间戳,把时间戳强转成 unsigned int 传给 srand,就能拿到动态变化的种子:
srand((unsigned int)time(NULL));⚠️注意:srand 写在 main 函数开头,不要放到循环 / 游戏函数内部反复调用。
4. 指定随机数范围公式
- 1‑100:
rand() % 100 + 1 - a~b 通用公式:
a + rand() % (b - a + 1)
二、基础版猜数字游戏需求
- 菜单:1 玩游戏,0 退出
- 选 1,电脑生成 1‑100 随机数
- 用户输入猜测,提示猜大 / 猜小,猜对结束本局
- 游戏结束回到菜单,可以重复游玩
基础版完整代码:
#include <stdio.h> #include <stdlib.h> #include <time.h> void menu() { printf("***********************\n"); printf("****** 1. play ******\n"); printf("****** 0. exit ******\n"); printf("***********************\n"); } void game() { int r = rand() % 100 + 1; int guess = 0; while (1) { printf("请猜数字>:"); scanf("%d", &guess); if (guess < r) { printf("猜小了\n"); } else if (guess > r) { printf("猜大了\n"); } else { printf("恭喜你,猜对了\n"); break; } } } int main() { int input = 0; srand((unsigned int)time(NULL)); do { menu(); printf("请选择:>"); scanf("%d", &input); switch (input) { case 1: game(); break; case 0: printf("游戏结束\n"); break; default: printf("选择错误,重新选择\n"); break; } } while (input); return 0; }三、扩展功能(课程加餐)
课程给出两个扩展任务:
- 限制最多猜 5 次,5 次全部猜错直接判定游戏失败,公布正确数字。
- 增加计时功能,统计本局游戏花费秒数。
扩展后 game 函数示例
void game() { int r = rand() % 100 + 1; int guess = 0; int count = 5; //最多5次机会 time_t start = time(NULL); //记录开始时间 while(count > 0) { printf("剩余%d次机会,请猜数字>:", count); scanf("%d", &guess); if (guess < r) { printf("猜小了\n"); } else if (guess > r) { printf("猜大了\n"); } else { time_t end = time(NULL); printf("恭喜你,猜对了!本局用时:%lld秒\n", end - start); return; } count--; } //次数耗尽 time_t end = time(NULL); printf("机会用完,游戏失败!正确数字是:%d,本局用时:%lld秒\n", r, end - start); }四、踩坑总结
- srand 不要写在 game () 里面,如果每一局都调用 srand,短时间多次运行会得到相同种子,随机数失效。只在 main 开头调用一次。
- rand ()%100 得到 0‑99,想要 1‑100 必须 + 1,很容易漏掉。
- time 返回 time_t 类型,传给 srand 需要强制转换
(unsigned int)。 - do‑while 循环适合菜单场景:先执行一次菜单,再判断是否继续。
五、学习感悟
这个小游戏看着简单,但综合了:函数封装、do‑while 菜单循环、while 游戏循环、switch 分支、库函数使用。写的时候要理清整体流程:显示菜单→接收选择→进入游戏→循环猜数→结束回到菜单。
后续学习嵌入式 C,很多逻辑也是这种模式:菜单、状态循环、库函数调用,把基础小游戏写熟,对以后写单片机业务逻辑很有帮助。
后续博客继续更新 C 语言进阶学习记录。