C语言程序设计第7天/猜数字游戏与个人解析

📅 2026/7/22 11:00:00 👁️ 阅读次数 📝 编程学习
C语言程序设计第7天/猜数字游戏与个人解析

猜数字游戏

  • 电脑自动生成1~100的随机数;
  • 玩家猜数字,猜数字的过程中根据猜的数字大小给出大了或小了的反馈,直到猜对游戏结束。

流程图

代码实现

#include<stdio.h> #include<stdlib.h> //生成随机数函数头文件 #include<time.h> //time时间戳头文件 void game(){ //将游戏逻辑和过程封装进函数game int input_num = 0; //将用户猜的数字储存 int r = rand() % 100 + 1; //随机生成1-100中的一个数 printf("Please type a number\n"); do { int ret = scanf("%d",&input_num); if(ret != 1) { while(getchar() != '\n'); printf("Wrong input! Please enter num\n"); continue; //执行完不退出循环,跳过这一轮重新输入 }if (input_num == 101) { printf("You gave up!\n"); return; // 直接退出 game 函数 }else if (input_num < r){ printf("The entered number is smaller than it\n"); //如果小于生成的随机数则提示小了 }else if (input_num > r){ printf("The entered number is bigger than it\n"); //如果大于生成的随机数则提示大了 } } while (input_num != r); //输入的数字不等于随机数时循环到上面重新输入数字 printf("Congratulations on beating it!\n"); //答对了 printf("Do you want to go again?\n"); } int main(){ srand((unsigned int) time (NULL)); //将time返回的时间戳强制转换为int类型给srand;使srand生成的种子每次都不一样 int input = 0; do { printf("--------------\n"); printf("----1.play----\n"); printf("----0.eixt----\n"); printf("-Please enter-\n"); printf("--------------\n"); scanf("%d",&input); //选择1或0 switch (input) { case 0: printf("Exit Game byebye!\n"); break; case 1: printf("Start Game\n"); game(); //玩游戏的函数 break; default: printf("Error, please choose 1 or 0 again\n"); //用户输入非1或0的数据提示错误,重新输入; break; } } while (input); return 0; }

项目场景1

我发现如果用户按错了输入成其他字符或字母时程序会出现死循环,我试图解决这个情况;

问题描述

问题:当运行时我在猜数字阶段输入非整型后程序自动循环一句话“The entered number is smaller than it”;


原因分析

可能是由于输入非整型后scanf读取失败,a留在缓冲区,返回0后判断为The entered number is smaller than it。小于随机数,同时scanf不会把错误字符从缓冲区移除,导致无法重新输入数据而无限循环,可以加入一段重制scanf的代码;


解决方案

加入了一段判定是否为异常数据的if语句,但其中的语句并没有学过;


项目场景2

我希望在进行猜数字的过程中用户可以随时退出,于是添加新的if判断是否需要退出程序;


问题描述

问题:输入101后无法退出;


原因分析

检查了代码都没有问题,可能是exe文件还是旧版;


解决方案

新建了一个c语言文件将代码复制过去运行发现没问题,判断为exe文件未及时更新,中断所有进程重新编译运行可以使用了;


随机数生成

rand函数

使用C语言中的rand函数可以生成随机数

int rand(void)

使用rand函数与srand函数前需要包含一个头文件:<stdlib.h>

而rand函数生成的随机数其实是一个伪随机数,范围在0~RAND_MAX之间,RAND_MAX的大小依赖编译器,大部分编译器上是32767

printf("rand num:%d",rand()); //带括号为rand生成的随机数;

printf("rand num:%d",rand); //不带括号为rand这个函数在内存中的地址;

之所以运行时,不带括号的每次都不一样看着更像随机数的原因是

  • 现代操作系统使用了"地址空间布局随机化"
  • 每次程序启动时,操作系统故意把函数、变量加载到内存中的不同位置,就像每次搬家时把家具摆在不同房间一样。
  • 这样做是为了安全:防止黑客通过固定地址发起攻击(比如缓冲区溢出攻击)

而带括号的rand生成的就像上面说的,是伪随机数。它是基于“种子”计算得出。

  • 如果你不调用srand()设置种子,C语言默认种子是1

  • 种子相同 → 算法相同 → 生成的随机数序列完全相同

所以每次运行程序时rand()输出的随机数都是一样的。

那么如何让rand()的种子变化,可以使用srand函数


srand函数

为rand()函数设置随机数生成器的“种子”。

#include <stdlib.h>
void srand(unsigned int seed);

  • void:这个函数什么都不返回,不会像scanf一样返回0和非0;
  • srand:函数名,全称是“seed Rand”(设置随机的种子);
  • unsigned int:意为调用这个函数时必须要传一个unsigned int类型的数字(非负整数)
  • seed:表示你传进来的数字会被当做种子使用
  • 可以传任何的unsigned int 值如:0、100、99999、time(NULL)返回的时间戳、123等

在rand函数中的用法:

srand((unsigned)time(NULL));

可以理解为

time(NULL)

返回当前时间戳(如 1698765432,类型 time_t)

(unsigned)强制转换

转成 unsigned int(如 1698765432,可能截断)

srand(1698765432)

种子被存入内部全局变量

之后每次调用 rand(),都从这个种子开始推算

在用srand设置好种子后,rand函数不需要做任何修改或接收额外参数。每次运行程序时调用rand()的时候就会根据srand的种子自动计算好。


time函数

使用time函数前需要添加<time.t>头文件

在学习过程中通常是使用程序运行的时间作为种子,因为时间是时刻在变化的。那么可以使用time函数:

#include <time.h>
time_t time(time_t *timer);

  • time_t:返回值类型:时间戳(从1970年1月1日到现在的秒数)
  • time:函数名
  • time_t*timer:参数:一个指向time_t的指针(可以传NULL(只取返回值))

time函数的参数timer 如果是非NULL的指针的话,函数也会将这个返回的差值放在timer指向的内存中带回去。
如果timer是 NuLL,就只返回这个时间的差值。time函数返回的这个时间差也被叫做:时间戳。

时间戳:从某个固定的时间点开始,到现在一共经过了多少秒(或毫秒)


题外理解:getchar

在项目场景1中我使用了while(getchar() != '\n');来进行进一步的程序完善

while(getchar() != '\n');

这句话的意思当getchar读取的字符不是回车符时就执行循环。


while((c = getchar()) != '\n');

给这段代码加上变量的话就可以保存读到的字符

图解:

执行代码后

getchar的特性是读取并返回字符,是否存储取决于自己有没有添加变量存储读取的字符;scanf的特性是根据格式读取并存储,失败的会留在缓冲区;这两个函数刚好可以补齐短板。