想在C语言里做一个能和朋友互动的小游戏?猜数字绝对是最经典的入门选择——不用复杂的图形界面,几行代码就能实现‘电脑出题、玩家猜数’的完整逻辑。今天我们就从随机数生成这个核心问题入手,一步步拆解一个能运行、有反馈的猜数字游戏,从基础版到带次数限制的进阶版,让你看懂每一行代码的作用。
一、游戏核心需求
1. 电脑生成1~100的随机数;
2. 玩家猜数,程序反馈“大了/小了”,直至猜对结束。
二、随机数生成的三层核心函数
1. 伪随机数生成:rand()
• 原型:
int rand(void);
• 功能:rand()返回的整数范围是 0 \sim \text{RAND_MAX},其中RAND_MAX是<stdlib.h>头文件中定义的宏,多数编译器(如VC++、GCC)将其定义为32767(即 2^{15} - 1),这是16位有符号整数的最大值。
• 头文件:<stdlib.h>;
• 缺陷:默认种子为1,每次运行程序生成的随机数序列完全相同(伪随机)。
2. 随机数种子初始化:srand()
• 原型:
void srand(unsigned int seed);
• 功能:为rand()设置随机数种子,种子不同则rand()生成的序列不同;
• 头文件:<stdlib.h>;
• 关键:需传入动态变化的种子才能实现真正的“随机”。
3. 动态种子获取:time()
• 原型:
time_t time(time_t* timer);
• 功能:返回从1970年1月1日00:00:00 UTC到程序运行时刻的秒数差值(时间戳);
• 参数说明:
◦ 若timer为NULL:直接返回时间戳;
time(NULL);//调用time函数返回时间戳,这里没有接收返回值
◦ 若timer为非空指针:将时间戳存入timer指向的内存空间;
• 返回值类型:time_t,本质是32位/64位整型(随编译器和系统而定);
• 头文件:<time.h>;
• 作用:利用时间的实时变化特性,作为srand()的种子,保证每次运行的种子唯一。
三、time_t类型的底层定义(以VS2022为例)
#ifndef _CRT_NO_TIME_T
#ifdef _USE_32BIT_TIME_T
typedef _time32_t time_t; // 32位整型
#else
typedef _time64_t time_t; // 64位整型
#endif
#endif
typedef long _time32_t;
typedef __int64 _time64_t;
四、随机数范围的通用设置方法
rand()生成的随机数默认范围是0 \sim \text{RAND_MAX},通过取模和偏移可自定义范围,具体实现和原理如下:
1. 生成0~99的随机数
rand()%100; //余数的范围是0-99
原理是对100取模,余数的自然范围就是0到99。
2. 生成1~100的随机数
rand()% 100 + 1;//%100的余数是0~99,0~99的数字+1,范围是1~100
原理是先通过取模得到0~99的数,再加1后,范围就映射为1到100。
3. 生成100~200的随机数
100 + rand()%(200 - 100+1)
//余数的范围是0~100,加100后就是100~200
原理是先取0~100的随机数,再加上100做偏移,最终得到100到200的数。
4. 生成a~b的随机数(通用公式)
a + rand()%(b - a + 1)
原理是先取0~(b-a)的随机数,再加上a做偏移,就能覆盖a到b的所有整数。
关键注意点:srand()函数只需在程序运行时调用一次即可,频繁调用会导致生成的随机数序列重复,失去随机性。
正确生成1~100随机数的代码:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
// 用时间戳初始化随机数种子
srand((unsigned int)time(NULL));
// 生成1~100的随机数(rand()%100得到0~99,加1后范围为1~100)
int random_num = rand() % 100 + 1;
return 0;
}
五、伪随机数的本质
伪随机”指rand()并非生成真正的随机数,而是通过固定算法基于“种子”计算得到的数序列。若种子不变(如默认的1),每次运行程序生成的数序列完全相同;只有通过srand()设置动态种子(如time(NULL)),才能让序列表现出“随机”效果。
rand()通过固定算法基于“种子”生成数序列:
1. 种子固定 → 序列固定(如默认种子1,每次运行随机数相同);
2. 种子动态(如time(NULL))→ 序列每次不同(实现“随机”效果)。
六、基础版猜数字游戏代码
实现菜单选择、随机数生成、玩家猜数反馈的核心逻辑,代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// 游戏逻辑函数:实现猜数和反馈
void game() {
// 生成1~100的随机数
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;
}
}
}
// 菜单函数:展示游戏选项
void menu() {
printf("*************************\n");
printf("******* 1. play *********\n");
printf("******* 0. exit *********\n");
printf("*************************\n");
}
int main() {
int input = 0;
// 初始化随机数种子,保证每次运行随机数不同
srand((unsigned int)time(NULL));
do {
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input) {
case 1:
game(); // 选择1,开始游戏
break;
case 0:
printf("游戏结束\n"); // 选择0,退出游戏
break;
default:
printf("选择错误,重新选择\n"); // 输入其他值,提示错误
break;
}
} while (input); // 当input为0时,退出循环
return 0;
}
七、进阶版(带5次猜数次数限制)
在基础版的基础上增加猜数次数统计,5次未猜对则判定失败,代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// 带次数限制的游戏逻辑函数
void game() {
int r = rand() % 100 + 1;
int guess = 0;
int count = 5; // 设置5次猜数机会
while (count) {
printf("\n你还有%d次机会\n", count);
printf("请猜数字:>");
scanf("%d", &guess);
if (guess < r) {
printf("猜小了\n");
} else if (guess > r) {
printf("猜大了\n");
} else {
printf("恭喜你,猜对了\n");
break; // 猜对则跳出循环,结束本轮游戏
}
count--; // 每次猜错,机会数减1
}
// 机会用完仍未猜对,提示失败并显示正确答案
if (count == 0) {
printf("你失败了,正确值是:%d\n", r);
}
}
// 菜单函数(与基础版一致)
void menu() {
printf("*************************\n");
printf("******* 1. play *********\n");
printf("******* 0. exit *********\n");
printf("*************************\n");
}
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;
}
这个小小的猜数字游戏,其实是C语言入门的“缩影”——从随机数的种子到玩家的交互,每一行都是基础逻辑的落地。
现在你已经能跑通完整代码,不妨试着改改次数、调调范围,甚至加个“难度选择”的小功能。编程的好玩之处,就在于把这些简单逻辑,变成属于你的、能互动的小玩意儿。
999

被折叠的 条评论
为什么被折叠?



