C语言入门 | “猜数字”小游戏 保姆级详解

📅 2026/8/5 11:39:44
C语言入门 | “猜数字”小游戏 保姆级详解
一、游戏要求1.电脑自动生成1~100的随机数2.玩家猜数字猜数字过程中根据猜测数据的大小给出大了或小了的反馈直到猜对游戏结束。二、初步逻辑分析1.布置游戏菜单使得游戏可以无限地玩下去每一局结束后玩家可以自己选择是要继续还是退出2.玩游戏过程生成随机数循环猜测三、随机数生成原理1.rand函数首先是需要函数 int rand(void)。即使你从来没见过这个函数但顾名思义大概是一个生成随机数的函数没错它就是用来生成随机数的。rand函数会返回一个伪随机数这个随机数的范围是在0~RAND_MAX之间这个RAND_MAX的大小是依赖编译器上实现的但是大部分编译器上是32767.但仅仅使用rand函数就可以了吗我们来验证一下int main() { printf(%d\n, rand()); printf(%d\n, rand()); printf(%d\n, rand()); return 0; }读者可以自行尝试将这段代码在自己的电脑多次运行是不是始终是这个结果。如果是这样那又何来的“随机”呢原来只有rand函数本身生成的是伪随机数。它是对一个叫“种子”的基准值进行运算生成的随机数而默认的“种子”是“1”。2.srand函数那么如何改变“种子”呢C语言又提供了一个函数 void srand (unsigned int seed)是用来初始化随机数的生成器的即通过参数seed设置“种子”。如下图int main() { srand(2); printf(%d\n, rand()); printf(%d\n, rand()); printf(%d\n, rand()); return 0; }int main() { srand(3); printf(%d\n, rand()); printf(%d\n, rand()); printf(%d\n, rand()); return 0; }那么问题又来了既然要随机数那就要求“种子”是动态变化的如果做到这一点呢这里就又不得不介绍一个新的函数3.time函数time_t time (time_t* timer)返回值1970年1月1日0时0分0秒到现在程序运行时间之间的差值单位是秒返回类型time_t 本质上就是32位或者64位的整型类型参数指针这里不细讲如果timer是NULL空指针就只返回这个时间的差值。这个时间差也被叫做时间戳。了解了以上内容我们就可以生成真随机数了#include stdio.h #include stdlib.h #include time.h int main() { srand((unsigned int )time(NULL)); printf(%d\n, rand()); printf(%d\n, rand()); printf(%d\n, rand()); return 0; }4.注意事项当然使用rand和srand函数需包含头文件stdlib.h,使用time函数需包含头文件time.h。还有一个细节问题细心的读者应该会发现这里有一个强制类型转换。因为time函数返回值的数据类型是time_t是32位或64位的整型类型而srand函数的参数需要的数据类型是32位的unsigned int类型所以进行了强制类型转换。以下这段算是插曲笔者的个人思考可略过不读笔者写到这里的时候还产生了一个问题随着时间的不断推移time函数返回值越来越大如果有一天超过了time_t数据类型能存放的最大值该怎么办从某个时间开始强制类型转换的过程中不会丢失数据吗因此查阅了一些资料。以下是分析过程unsigned int 取值范围0~42949672960~32位整型取值范围-2147483648~2147483647~如果某个编译器的time_t类型是32位整型那么在2038年时间戳就会超过其所能存放的最大值这就是“2038危机”好在现在大多数编译器都采用64位整型如果是64位整型那么time函数距离原生溢出还有约2922亿年的距离但是强制类型转换之后会把后32位截断使得在2106年触发数据丢失但好像离现在还有一断距离。最后一个问题我们如何产生指定范围内的随机数呢比如产生1~100的随机数。 rand()%1001 为什么是这样我们一步一步来分析 先是rand%100这代表产生0~99的整数可理解为定步长 再是“1”这代表要从1开始可理解为定起点 因此可以总结出一个公式a~b的随机数 rand()%(b-a1)a#include stdio.h #include stdlib.h #include time.h int main() { srand((unsigned int)time(NULL)); printf(%d\n, rand() % 100 1); printf(%d\n, rand() % 100 1); printf(%d\n, rand() % 100 1); printf(%d\n, rand() % 100 1); printf(%d\n, rand() % 100 1); return 0; }四、代码的实现PS由于笔者不想篇幅过长缺乏可读性所以下面的每段代码忽略调试截图但代码一定是经过调试的如果读者有兴趣也可以在自己的电脑上进行验证1.布置游戏菜单将游戏菜单通过printf函数打印出来不用很花里胡哨但要有“玩”和“退出”的选项以及用户的选择机会#include stdio.h int main() { int input 0; printf(--------------------\n); printf(---- 1.play ----\n); printf(---- 0.exit ----\n); printf(--------------------\n); printf(请选择); scanf(%d, input); return 0; }这里为什么设置“1”和“0”而不是别的和后面的循环条件有关后面会有说明根据用户输入值的不同程序需要作出不同的反应因此这里需要一个选择结构选择“1”就玩游戏选择“0”就退出游戏选择其他的就提示选择错误。if语句和switch语句都可以但是switch更简洁。#include stdio.h int main() { int input 0; printf(--------------------\n); printf(---- 1.play ----\n); printf(---- 0.exit ----\n); printf(--------------------\n); printf(请选择); scanf(%d, input); switch (input) { case 1: printf(玩游戏\n); //这里要写玩游戏的程序但是为了调试方便暂时先这样写 break; case 0: printf(退出游戏\n); break; default: printf(没有这个选项请重新选择\n); break; } return 0; }很明显的是在这里需要一个循环结构使得这个程序会无限循环除非用户自己不想玩了。那么while/for/do while三种循环语句用哪种比较好呢显然这里用do while会比较合适因为这段程序至少需要被执行一次。#include stdio.h int main() { int input 0; do { printf(--------------------\n); printf(---- 1.play ----\n); printf(---- 0.exit ----\n); printf(--------------------\n); printf(请选择); scanf(%d, input); switch (input) { case 1: printf(玩游戏\n); //这里要写玩游戏的程序但是为了调试方便暂时先这样写 break; case 0: printf(退出游戏\n); break; default: printf(没有这个选项请重新选择\n); break; } } while (input); return 0; }前面提到的为什么菜单打印“1”和“0”供用户选择原因就在于这样可以让循环结构的条件判断更加简洁。在C语言中0代表假非0代表真因此让“1”代表玩游戏“0”代表退出游戏然后将存放用户输入数据的变量input直接作为循环是否继续进行的判断条件是非常巧妙的。2.编写玩游戏的程序显然当用户选择“1”选项后应该进行玩游戏的过程。整个游戏的程序不说逻辑多复杂但至少没个二十行代码应该是下不来的。所以如果这个代码块直接写在case 1的分支下面是非常影响可读性的因此将整个玩游戏的程序封装成一个函数是一个不错的选择。#define _CRT_SECURE_NO_WARNINGS #include stdio.h void game() { } int main() { int input 0; do { printf(--------------------\n); printf(---- 1.play ----\n); printf(---- 0.exit ----\n); printf(--------------------\n); printf(请选择); scanf(%d, input); switch (input) { case 1: game(); break; case 0: printf(退出游戏\n); break; default: printf(没有这个选项请重新选择\n); break; } } while (input); return 0; }下面我们主要关注玩游戏的程序。首先是自动生成随机数然后给用户猜测的机会。#include stdio.h #include stdlib.h #include time.h void game() { int r rand()%1001; int guess 0; printf(请猜数字); scanf(%d, guess); } int main() { int input 0; srand((unsigned int)time(NULL)); do { printf(--------------------\n); printf(---- 1.play ----\n); printf(---- 0.exit ----\n); printf(--------------------\n); printf(请选择); scanf(%d, input); switch (input) { case 1: game(); break; case 0: printf(退出游戏\n); break; default: printf(没有这个选项请重新选择\n); break; } } while (input); return 0; }至于为什么种子是放在main函数里面而不是game函数里面或许是因为整个程序中srand函数只调用一次放在前面更简洁明了笔者不才这个解释都说服不也自己那就更别提给别人解释清楚了询问AI感觉也不太明白自己也还在持续学习当中也许是知识储备还不够读者如果感兴趣可以去自行搜索相关资料。根据用户输入的数字程序需要提示用户是猜大了还是猜小了因此这里需要选择结构显然if语句是比较合适的。void game() { int r rand()%1001; int guess 0; printf(请猜数字); scanf(%d, guess); if (guess r) printf(猜小了\n); else if (guess r) printf(猜大了\n); else printf(恭喜你猜对了\n); }当然不可能只给一次机会现在假设可以猜无数次那么就需要循环结构。这里采用while循环因为不知道要猜多少次所以可先设置一个死循环循环条件为“1”。void game() { int r rand()%1001; int guess 0; while (1) { printf(请猜数字); scanf(%d, guess); if (guess r) printf(猜小了\n); else if (guess r) printf(猜大了\n); else printf(恭喜你猜对了\n); } }但是呢也不能一直循环猜对了之后本次游戏就结束了应该显示最初的游戏菜单才对用户可以自行选择要不要再次游戏这样逻辑才是通顺的。因此用户猜对应跳出循环void game() { int r rand()%1001; int guess 0; while (1) { printf(请猜数字); scanf(%d, guess); if (guess r) printf(猜小了\n); else if (guess r) printf(猜大了\n); else { printf(恭喜你猜对了\n); break; } } }这样这个猜数字小游戏的代码就全部编写完成了下面是所有的代码可供参考。#include stdio.h #include stdlib.h #include time.h void game() { int r rand()%1001; 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 { printf(--------------------\n); printf(---- 1.play ----\n); printf(---- 0.exit ----\n); printf(--------------------\n); printf(请选择); scanf(%d, input); switch (input) { case 1: game(); break; case 0: printf(退出游戏\n); break; default: printf(没有这个选项请重新选择\n); break; } } while (input); return 0; }五、加花部分1.设定可猜测次数也许我们还可以设置一下可猜测的次数比如最多能猜5次。如何实现呢可以定义一个循环变量初始值是5使其每猜一次就-1直到变为0跳出循环。void game() { int r rand()%1001; int guess 0; int count 5; while (count) { printf(请猜数字); scanf(%d, guess); if (guess r) printf(猜小了\n); else if (guess r) printf(猜大了\n); else { printf(恭喜你猜对了\n); break; } count--; } }这样还是感觉缺少点什么。猜测成功时打印恭喜用户那么猜测失败是不是也同样需要告知用户呢并且最好告诉他正确值是多少。很明显猜测失败后用printf函数打印的那句话是需要放在循环外面的。当然这里我们又要考虑一个问题。现在跳出循环有2种可能一种是猜对了break跳出循环;另一种是猜测次数用完了没有猜对跳出循环。那就需要一个if语句进行一次判断了判断条件是什么呢很容易联想到我们上面定义的循环变量count。只有当count变量等于0时才代表是猜测失败了跳出循环否则是猜对了才跳出循环因此我们有了以下代码void game() { int r rand()%1001; int guess 0; int count 5; while (count) { printf(你还有%d次机会\n,count); printf(请猜数字); scanf(%d, guess); if (guess r) printf(猜小了\n); else if (guess r) printf(猜大了\n); else { printf(恭喜你猜对了\n); break; } count--; } if (count 0) printf(很遗憾5次机会已使用完正确值是%d\n, r); }2.计时猜测我们是否还可以为玩家记录一下他所用的时间呢答案当然是可以的。怎么实现呢前面我们了解了时间戳的概念那么就可以很自然的想到在游戏开始时我们计算一下时间戳在游戏结束时再计算一下时间戳两个时间戳相减就可以得到啦void game() { int r rand()%1001; int guess 0; int count 5; time_t start time(NULL); while (count) { printf(你还有%d次机会\n,count); printf(请猜数字); scanf(%d, guess); if (guess r) printf(猜小了\n); else if (guess r) printf(猜大了\n); else { printf(恭喜你猜对了\n); break; } count--; } time_t end time(NULL); if (count 0) printf(很遗憾5次机会已使用完正确值是%d\n, r); printf(本次游戏用时%lld秒\n, end - start); }再说明一个细节问题time函数返回值的数据类型是time_t类型具体前文有提到笔者使用的编译器默认time_t类型是64位整型因此printf函数打印时用的占位符是%lld和 long long int 数据类型大小也是64位使用的占位符相同。六、完整代码供参考#include stdio.h #include stdlib.h #include time.h void game() { int r rand()%1001; int guess 0; int count 5; time_t start time(NULL); while (count) { printf(你还有%d次机会\n,count); printf(请猜数字); scanf(%d, guess); if (guess r) printf(猜小了\n); else if (guess r) printf(猜大了\n); else { printf(恭喜你猜对了\n); break; } count--; } time_t end time(NULL); if (count 0) printf(很遗憾5次机会已使用完正确值是%d\n, r); printf(本次游戏用时%lld秒\n, end - start); } int main() { int input 0; srand((unsigned int)time(NULL)); do { printf(--------------------\n); printf(---- 1.play ----\n); printf(---- 0.exit ----\n); printf(--------------------\n); printf(请选择); scanf(%d, input); switch (input) { case 1: game(); break; case 0: printf(退出游戏\n); break; default: printf(没有这个选项请重新选择\n); break; } } while (input); return 0; }最后非常感谢小伙伴能阅读到这里欢迎留言提问或讨论。完