目录
Test1:字符汇集
编写代码,演示多个字符从两端移动,向中间汇聚。
代码:
#include<stdio.h>
#include<string.h>
#include<Windows.h>
//Test1:字符汇集
//编写代码,演示多个字符从两端移动,向中间汇聚。
int main()
{
char arr1[] = "Welcome to China!!!";//数组长度-19个元素(算空格)arr1[20]
char arr2[] = "*******************";//数组长度-19个*
int left = 0;//左指针
int right = strlen(arr1) - 1;//右指针
while (left<=right)
{
arr2[left] = arr1[left];
arr2[right] = arr1[right];
printf("%s\n", arr2);
Sleep(1000);
system("cls");
left++;
right--;
}
printf("%s\n", arr2);
return 0;
}
代码解析:
1.因此我们需要两个数组来存储这两组字符串,一组字符串里面放Welcome to China!!!,另外一组放*******************。因为要实现字符向中间移动,所以两个数组的长度要保持一致。
2.这里我定义了两个指针,一个左指针,一个右指针,左、右指针每次移动一次,就各自打印左、右字符。这里初始化定义左指针等于0,因为数组的下标是从0开始的,初始化右指针等于strlen(arr1)-1,其实这里也可以等于strlen(arr2)-1,因为刚才在定义数组时,arr1数组长度等于arr2数组长度。这里的strlen函数作用就是计算数组大小,strlen函数包含在string.h的头文件里面,因此在代码前要加一个包含string.h的头文件-#include<string.h>.(比如一个数组里面有10个元素,那么这个数组的下标就0~9。)
*Don't worry! 数组后面也会为大家总结!
3.当左、右指针相等时,把arr1数组里的内容给arr2数组,并打印arr2数组里面的内容。因为我们知道到这里只是打印了一次,想要打印完,需要借助循环,当打印完一次后,左指针向后移动,即左指针+1,右指针向前移动,即右指针+1。因为我不确定这里需要打印多少次,所以不能用for循环,这里我采用while循环,那么while循环的条件是什么呢?通过观察,打印时,左指针小于右指针时,正常打印,当左指针等于右指针相等时,打印完最后一个字符o,所以循环执行的条件是left<=right。
4.当写到这里,其实屏幕上就已经可以打印字符向中间移动了,只不过是直接静态打印在屏幕上,如下图:
如果我们想要打印的更好看,例如字符一个一个跳动的打印出来,那么应该怎么办呢?这里介绍Sleep函数-Sleep函数是实现睡眠,单位是毫秒,包含在windows.h这个头文件里面,所以在代码前面我们要包含windows.h这个头文件-#include<Windows.h>。在Windows环境里,Sleep的S要大写,在Linux的环境里s小写。当加入这个函数之后,打印的效果如下图所示:
这样就不会像之前一样,是直接出现在屏幕上,这个是变化跳动出现的。
5.写到上述的一步后,代码运行,当光标停止闪烁,最后打印在屏幕上的依然如下图所示:
如果我想要在一行上实现字符跳动打印,应该怎么办呢?这里我加入system("cls"),system是一个库函数,可以执行系统命令,cls是清空屏幕的一个命令。
(简述:系统命令,我们使用的Windows系统是图形化显示界面,真正的命令是由系统命令发出的。我们可以在自己的电脑搜索框里输入cmd打开系统命令框,例如:显示当前目录的所有文件,输入 dir,如果要清除屏幕上的内容,就输入cls。)如下列长图所示:
这时候我们再次运行程序,效果如下图所示:
这个时候就是在屏幕的一行跳动打印了,不过可惜的的是跳动打印完成后,屏幕上就没有了,被清屏了。如下图所示:
如果这里我想等跳动打印结束后,Welcome to China!!!依然停留在屏幕上,应该怎么做呢?只需在循环结束后,加上一个printf("%s\n",arr2);就行,这个时候arr2里面就已经是arr1里面的内容了。
Test2:模拟登录
编写代码实现,模拟用户登录情景,并且只能登陆录三次。(只允许输入三次密码,如果密码正确则提示登录成功,如果三次均输入错误,则退出程序。)
#include<stdio.h>
#include<string.h>
//模拟登录
int main()
{
//假设我的登陆密码是字符串"123456"
char password[20] = { 0 };//把输入的密码存放在password字符串数组里面
int i = 0;
int flag = 0;//判断是否登陆成功
for (i = 0; i < 3; i++)
{
printf("请输入密码\n");//循环输入提示
scanf("%s", password);//循环输入密码 数组名不需要取地址&password,加上也行
int ret = strcmp(password, "123456");
if (0==ret)
{
printf("登陆成功\n");
flag = 1;
break;
}
else
{
printf("第%d次输入失败\n",i+1);
}
}
//break以及三次登录失败都会来到这
//flag判断是否成功登录
if (0 == flag)
printf("登陆失败,请退出程序\n");
return 0;
}
代码解析:
1.这里我假设正确的登录密码是字符串"123456"。每次输入的密码与字符串"123456"对比,那么我就需要把我输入的密码用一个字符数组存起来,所以定义一个字符数组,数组大小随便给一个值,不要太小就行,以免数据溢出,char password[20]。
2.因为要实现最多登录三次,即只能最多输入三次密码,所以这里采用for循环,i从0开始,循环三次,i<3。如果登陆成功,就显示登陆成功,并跳出循环;如果登陆失败,就显示第几次输入密码错误,这里的i是物理顺序(即计算机的顺序),我们这里要使用人类较为熟悉的逻辑顺序,即i+1。3当循环三次,三次密码均属入错误,就跳出循环。
3.正确输入密码,执行break可以来到循环外面,三次登陆失败也会来到循环外面,那么怎么判断是正确输入密码跳到这,还是三次登陆失败来到这呢?于是我在循环开始前定义一个flag整型变量,int flag=0,即当输入错误密码时,flag不会发生变化,当输入正确密码后,执行分支语句if,将flag赋值为1。结束循环后,if判断flag,当flag依然等于0,就表明三次登陆失败,提示退出程序。
4.最关键,也是容易出错的是怎么判断我的密码是否正确呢?这里有人可能想出这样的办法,如下列代码:
if (password == "123456")
{
printf("登陆成功\n");
flag = 1;
break;
}
调试运行,结果如下图所示:
这里明显输入密码正确,为什么却显示密码错误呢?这里告诉大家一个知识点,在比较两个字符数组时,不能直接使用==判断,要使用strcmp函数来比较两个字符数组。那么strcmp的用法是什么呢?将你要比较的两个参数传给strcmp,例如strcmp(参数1,参数2),strcmp会逐一比较两参数,那么它比较参数的什么呢?这里并不是比较两参数的长度,我们知道在计算机中,字符是以ASC码值存储在计算机当中的,因此strcmp会逐一比较两参数中字符的ASC码值,当参数1中的第一个字符码值小于参数2中的第一个字符码值,strcmp函数就会返回值<0;当参数1中的第一个字符码值大于参数2中的第一个字符码值,strcmp函数就会返回值>0;当参数1中的第一个字符码值等于参数2中的第一个字符码值,strcmp函数就会返回0。例如:
因此我们还要定义一个变量接受strcmp的返回值,int ret=strcmp(password,"123456");if判断,只有当ret=0时,表示输入密码正确。如此,一个简单的模拟登录程序就实现了。
Test3:猜数字游戏
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void game()
{
//生成1~100的随机数
int aim=rand()%100+1;
printf("游戏开始,请猜数\n");
//你猜的数字
int num = 0;
while (1)
{
scanf("%d", &num);//循环输入你猜的数字
//提示猜大猜小
if (num < aim)
{
printf("猜小了\n");
}
else if (num > aim)
{
printf("猜大了\n");
}
else
{
printf("猜对了\n");
//system("cls");//清理屏幕,根据个人喜好增加命令
break;
}
}
}
int main()
{
srand((unsigned int)time(NULL));
//游戏执行
int input = 0;
do
{
printf("\n请输入>>>\n0 结束游戏\n1 开始游戏\n");
scanf("%d", &input);
switch (input)
{
case 0:
break;
case 1:
game();
//system("cls");//清理屏幕,根据个人喜好增加命令
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
代码解析:
3.1程序整体框架
首先我们在写程序的时候,会先搭建一个程序的整体框架,这里我们需要思考,这个程序需要什么?首先我们会提示玩家,输入一个数,输入1代表玩游戏,输入0即退出游戏,所以要给出一个提示信息。当然有些玩家会输入别的数字,这里我们采用switch分支语句。定义一个输入变量input,当变量input为1时,执行游戏,这里我们只是先搭建一个整体框架,所以先假定有一个game()函数能实现我的游戏,之后我们再去实现game()函数;当变量input为0时,结束程序;当input为除1和0以外的数时,提示重新输入。
如果我想实现多轮游戏,这里就需要循环。这里不管玩家想不想玩游戏,程序一开始都要给出一个提示,所以是先做在判断,采用do...while(条件)循环,那么循环条件是什么呢?在C语言中,0表示假,非0表示真,而我们的输入input恰好对应这个环境,当input为0时,循环结束,游戏结束;当input为1时,程序可以继续循环;当input为除0和1以外的数字,不等于0,为真,可以提示输入错误,可以重新输入。整体框架代码如下所示:
#include<stdio.h>
int main()
{
int input = 0;
do
{
printf("请输入>>>\n0 结束游戏\n1 开始游戏\n");
scanf("%d", &input); //因为需要实现多轮游戏,所以需要输入多次,scanf需要放在循环里面
switch (input)
{
case 0:
break;
case 1:
game();
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
3.2实现函数game()
整体框架搭好后,重点在于怎么实现函数game(),使游戏真正运行起来呢?我们这里需要思考这个游戏由什么部分组成,通过分析,我们可以知道,需要两个部分,一个是程序生成随机数,另一个部分就是我们自己猜数字,程序会提示猜大了/猜小了/猜对了。
3.2.1生成随机数
首先解决第一个部分,如何生成随机数?在这里介绍一个C语言生成随机数的函数rand,其作用与用法如下图所示:
写到这一步,我们可以看看rand的效果,如下列代码:
#include<stdio.h>
#include<stdlib.h>
void game()
{
//生成随机数
int aim=rand();
RAND_MAX;
printf("%d\n", aim);
}
int main()
{
int input = 0;
do
{
printf("请输入>>>\n0 结束游戏\n1 开始游戏\n");
scanf("%d", &input); //因为需要实现多轮游戏,所以需要输入多次,scanf需要放在循环里面
switch (input)
{
case 0:
break;
case 1:
game();
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
调试程序,效果如下图所示:
看着是挺随机的哈,然而当再次调试程序时间,结果是什么呢?如下图所示:
结果发现,两次调试运行程序,生成的随机数都是一样的。这还玩个der啊,这样玩还有什么意思呢?那这里应该怎么办呢?我们可以回去看rand函数的定义,这里有一个规定,rand函数一般是搭配srand函数使用的,srand的定义如下图所示:
好的,这里我们加上srand函数,结果是什么样的呢?如下图所示:
srand函数需要一个无符号的整数,那我就给它一个无符号整数,可是我发现当每次输入都是相同的,只有当给它的数发生变化,它才发生变化,那这么说来,我还得给它一个变化的数,那我本来就是找你要随机数,现在你怎么还倒过来找我要随机数呢?这部陷入死循环了吗?放心,我不会给自己挖坑,山人自有妙计!
这里就要介绍另外一个知识点,我们知道时间是发生变化的,如果我们把时间作为参数传个srand,这不就解决了吗。那怎么把时间传给srand函数呢?时间戳就能解决这个问题,时间戳如下图所示:
他在C语言中的函数是time,如下图所示:
后面会为大家总结指针,这里就随便给它一个空指针,代码为:
srand(time(NULL));
//生成随机数
int aim=rand();
printf("%d\n", aim);
这里有可能会报错,我们需要给它强制转化一下数据类型(强制转化属于关键字,后面也会总结的。Don't worry!!!)
代码为:
srand((unsigned int)time(NULL));
这个时候我们再来看一下代码的调试效果,效果如下图所示:
会发现,这个时候生成的随机数依然还是不够随机,随机数的大小比较相近,那这究竟还有什么问题呢?这里简单说一下srand函数一般只需要被调用一次就好,不需要被频繁调用,而这里的game函数作为主函数中循环体的一部分,会被循环调用,因此不适合放在game函数中,我们中的main函数是只执行一次的,因此srand函数要放在main函数里面。此时代码就应该是:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void game()
{
//生成随机数
int aim=rand();
printf("%d\n", aim);
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
printf("请输入>>>\n0 结束游戏\n1 开始游戏\n");
scanf("%d", &input); //因为需要实现多轮游戏,所以需要输入多次,scanf需要放在循环里面
switch (input)
{
case 0:
break;
case 1:
game();
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
写到这一步,调试运行代码,其效果为:
这个时候生成的随机数就很随机了,可是我想要的随机数是1~100的随机数,应该怎么办呢?这里举一个简单的例子:例如我想要一个0~9之间的数,就用i%10,因为10的余数是0~9;如果想要0~17之间的数,就用i%18,因为18的余数是0~17,那么这里我想要1~100之间的数,就用i%100+1,i%100就是0~99之间的数,+1就是1~100的数字。因此代码为:
int aim=rand()%100+1;
3.2.2循环猜数字
实现生成随机数后,接下来我们就需要猜数字了。这里我们要定义一个变量来存储我们猜的/输入的数字,如果猜的数字不对,就要继续猜,因此这里要使用循环,因为这里我不知道要猜多少次,所以我使用while循环,循环条件为真,一直循环下去。如果我们猜的数字比生成的随机数小,就要提示猜小了;如果我们猜的数字比生成的随机数大,就要提示猜大了;如果我们猜的数字等于生成的随机数,就要提示猜对了并跳出循环。代码为:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void game()
{
//生成随机数
int aim=rand()%100+1;
int num = 0;
//猜数字
while (1)
{
printf("请输入猜的数\n");
scanf("%d", &num);// 因为需要猜多次猜中,所以需要输入多次,scanf需要放在while循环里面
if (num < aim)
{
printf("猜小了\n");
}
else if (num > aim)
{
printf("猜大了\n");
}
else
{
printf("猜对了\n");
break;
}
}
}
效果为:
这个时候基本就已经完成了,但是还是可以稍微追求一下美观,比如前面提到的清理屏幕。我设置清理屏幕的地方如题目下方整体代码所示。朋友们可以根据之间的习惯来设置。大致效果(未清理屏幕)如下图所示:
大家也可以添加一点自己的设计元素进去,例如T1的字符移动显示,作为游戏菜单显示界面。
好的,本次小结到这里结束,如有错处,望海涵,期待与大家共同交流知识,期待下次与大家的探讨!