在写这一篇博客之前,我一直在想要用什么样的方式给大家展现出来,是先把整个工程完成再去讲每段代码?还是按照代码的实现过程去一步一步推进?或许两者随便哪个都行,但是我觉得,如果想要把一个知识点讲透了,让读者能够跟着自己的文章一起去思考,并且能够独立完成这个项目,那么,我需要做的就不止这点了。
目录
前言:
项目功能的逐步实现:
一:开始前的准备,需求分析
二:项目模块化
三,函数的实现
1,main函数的设计
代码解析:
1)引用头文件的作用:
2)使用do while循环的逻辑:
3)switch 语句选择在本程序中的原理:
函数测试:
2,封装函数功能实现
2)game函数封装
代码解析:
1)生成随机数实现原理及方法:
2)设置所生成随机数范围的方法:
3)设置次数的逻辑:
代码测试:
四,项目的总体预览:
test.c
game.c
game.h
五,作者的话:
作为一个1~100之间的猜数字游戏,需求分析如下:
在项目中,我本人比较建议大家尽量进行函数模块化,这样可以使代码逻辑更加清晰,不论是自己还是别人都能够很好地去阅读代码。
例如:本项目我会分成三个模块:
在写函数的功能之前,我们应当先想清楚程序的运行逻辑,故在写main函数时,若是需要什么功能,可先写个函数名以及他的功能,等主函数完成后,再去一一实现,这样有利于逻辑思考的连续性。
根据需求分析得:该游戏需要提前打印菜单,并且用户可以选择开始或退出游戏,与此同时,该游戏在结束时需要能够让客户自行选择是否继续游戏。代码如下(选择用截图是因为编译器对关键字有颜色区分,可以看得清楚一点):
在代码第十行(左边行号)处有一段代码:#include “game.h” ,这个是包含我们自己所创建的头文件的作用 ,这样一来我们就可以把所有的函数引用,库函数头文件包含等等,通通写进game.h中,而我们只需要在主函数前包含这一个文件即可,如此可以使得代码看起来更简洁干净。
( 如果是包含库函数的头文件就是写成:#include <头文件名>,若是包含我们自己创建的头文件,就写成:#include “头文件名”)
之所以使用do while循环,主要是因为无论用户是否开始游戏,函数都会先打印菜单。
在主函数中,我设定了局部变量 input,并将其作为do while循环的判断条件。
在do while循环的判断条件中,非0为真,0为假。所以1为真,我们可以在case 1 下存放游戏函数,当用户输入1时,便会开始游戏,并且在游戏结束时break跳到do while判定,因为1为真,故继续执行循环,打印菜单...以此类推
而0为假,当用户输入0时,程序跳到case 0 语句再执行break跳出循环来到do while判定,因为0为假,故循环结束,退出游戏
而且为了防止用户乱输入,我们还应当加上 default 以纠正。 (default:根据用户输入的值,执⾏相应的 case 分⽀。如果找不到对应的值,就执⾏ default 分⽀)
main函数的逻辑完善后,我们还应当检验其是否能够以正确的方式输出我们想要的值,该代码输出如下:
可以看到,输出正常,证明逻辑没有出错。
根据需求分析得,当用户执行程序时,需要菜单来选择自己是开始游戏或者退出游戏,所以我们需要封装一个 menu 函数用于打印菜单。而封装的 menu 函数放入game.c的源文件中(game.c也需要包含头文件game.h)。如下图:
menu函数:这是我们自己封装的一个函数,主要作用就是打印菜单,所以无需传参,并且无需返回值,所以函数形式为:void menu();。
当我们完成函数的封装后,需要将函数的声明写入头文件中,如下:
根据需求分析,可以得出game()函数应当具备以下功能:
1,随机生成一个1~100之间的随机数
2,当我们在猜数字时,要根据与被猜数的距离给出相应的提示
3,设置猜的次数,超过次数则游戏结束
该函数无需返回任何值,故返回类型设置成void,并且无需传参。同样的,与menu函数相同,需要将函数引用放置在头文件game.h中,如下:
在讲生成随机数之前,我需要先给大家铺垫三个函数:
1,rand函数:C语⾔提供了⼀个函数叫 rand,这函数是可以⽣成随机数的。rand函数的使用需要包含头文件:stdlib.h。
但是当我们多次输出rand函数时,发现每次输出的随机数是一样的,如下:
不管运行多少次,所输出的随机值都与上一次结果相同,说明这是有问题的。
如果再深⼊了解⼀下,我们就不难发现,其实rand函数⽣成的随机数是伪随机的,伪随机数不是真正的随机数,是通过某种算法⽣成的随机数。真正的随机数的是⽆法预测下⼀个值是多少的。⽽rand函数是对⼀个叫“种⼦”的基准值进⾏运算⽣成的随机数。
之所以前⾯每次运⾏程序产⽣的随机数序列是⼀样的,那是因为rand函数⽣成随机数的默认种⼦是1。如果要⽣成不同的随机数,就要让种⼦是变化的。
2,srand函数:C语⾔中⼜提供了⼀个函数叫 srand,⽤来初始化随机数的⽣成器的。
//原型为:
void srand(unsigned int send);
程序中在调⽤ rand 函数之前先调⽤ srand 函数,通过 srand 函数的参数seed来设置rand函数⽣成随机数的时候的种⼦,只要种⼦在变化,每次⽣成的随机数序列也就变化起来了。那也就是说给srand的种⼦是如果是随机的,rand就能⽣成随机数;在⽣成随机数的时候⼜需要⼀个随机数,这就⽭盾了。
注意:srand函数每个工程只需要调用一次即可!
3,time函数:在C语⾔中有⼀个函数叫 time ,time函数的使用需要包含头文件:time.h。
//原型为:
time_t time(time_t*timer);
time 函数会返回当前的⽇历时间,其实返回的是1970年1⽉1⽇0时0分0秒到现在程序运⾏时间之间的差值,单位是秒。返回的类型是time_t类型的,time_t 类型本质上其实就是32位或者64位的整型类型。
time函数的参数 timer 如果是⾮NULL的指针的话,函数也会将这个返回的差值放在timer指向的内存中带回去。如果 timer 是NULL,就只返回这个时间的差值。time函数返回的这个时间差也被叫做:时间戳。
如果只是让time函数返回时间戳,我们就可以这样写:
time(NULL);//调用time返回时间戳,这里没有返回接收值
由上铺垫可得:我们如果用rand需要生成一个随机数,就需要调用srand函数来初始化rand函数的种子,而为了使种子随时在变化,我们就将时间戳设置为rand函数的种子,因为时间一直在变化,所以种子就一直在变化,同样的,随机数也一直在变化。
代码形式如下:
srand((unsigned int)time(NULL));
注意:srand函数一个工程只需要调用一次,故该段代码应当放在main函数中调用!
在我们设置好随机数后,需要再设置随机数的生成范围,在该项目中,我们需要生成1~100的随机数,方法及操作逻辑如下:
假设随机生成一个数n,我们只需将 n%100,那么n%100的数字便会变成0~99,我们只需操作为:n%100 + 1;此时生成的随机数的范围便是1~100;
在game()函数中,我将猜数字设置成while循环,并且将局部变量times设为判定条件。每次进入循环(猜数字)结束后,times--,故当times=0时,while判定为假,结束循环,即可实现。
可以看到,代码的所以功能都在我的设想当中,故没有问题。当然,整个程序还可以更加好,提示也可以更加细致,如根据不同的距离显示不同的提示等等,但是由于时间原因,我只是写了一个主体出来,如果大家有兴趣的话,可以接着将其优化。
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();//菜单
scanf("%d", &input);
switch (input)
{
case 1:
game();//游戏封装
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("非法输入,请重新输入\n");
break;
}
} while (input);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()
{
printf("************************\n");
printf("************************\n");
printf("******* 1:> play *******\n");
printf("******* 2:> exit *******\n");
printf("************************\n");
printf("************************\n");
return;
}
void game()
{
int count = rand() % 100 + 1;
int find = 0;
int times = 8;//猜数字次数
while (times)
{
printf("\n");
printf("你还有%d次机会 ",times);
printf("请输入您要猜的数字:> ");
scanf("%d", &find);
if (find < count)
{
printf("您猜小了,再猜大一点的数字\n");
}
else if (find > count)
{
printf("您猜大了,再猜小一点的数字\n");
}
else if (find == count)
{
printf("恭喜您,猜对了!\n");
break;
}
times--;
}
if (times == 0)
printf("游戏失败,正确数字为%d\n",count);
return;
}
#pragma once
#include
#include
#include
void menu();
void game();
整篇文章,我对于一些比较简单的内容讲的比较细致,比如switch语句,设置次数等等,主要是想帮助一些不懂的朋友理解这个代码这样写的原因,如果您觉得啰嗦了,可以在评论区留言,以便我下次改进。
目前我在考虑写一个有关扫雷实现的博客,但是扫雷我还有几个功能一直没能实现,等我彻底搞明白之后就会和大家分享!
谢谢大家的观看,再见!