目录
循环结构
1.浅析循环结构
不知道童鞋们记不记得上一篇,关于分支结构的文章里的关机病毒的案例呢?里面我们就用到了一个简单却经典的循环结构。
其实循环结构和顺序结构与分支结构一样,都是我们生活的一种抽象化。例如我们大多数同学都要经历学校——工作——退休,这是一种顺序结构;在学校上学或者参加工作,我们可以选择不同的学校和不同的城市,这是一种分支结构;在学校我们要日复一日的读书,上班了我们要日复一日的工作,退休了我们要日复一日的等待残生了却,再往大了看,一代又一代的人类都是要经历受受教育——社会建设——退休,这里面的循环往复又岂止眼前之语。
2.循环结构的介绍
我们通常使用的循环结构有:for 循环、while 循环、do_while 循环。
2.1 while循环
while (表达式)
{
语句
}
或
while (表达式) 单个语句
但后者却不是好的代码风格,我们应该切记C语言程序需要具备可读性与可扩展性。
这是 while 循环的执行流程:
(continue——跳出本次循环,break——终止循环)
是不是非常简单,我们的 while 语句先对表达式进行判断,表达式为真,即结果为非零数或 true (布尔类型),则执行语句,一直为真则一直执行,否则停止。
给出代码示例并分析如下:
#include<stdio.h>
int main() //打印1-10
{
int i = 1, input = 0;
scanf("%d", &input); //输入input的值
while (i < 11) //当i < 11,即i为1-10的数时表达式结果为真,返回值不为 0,循环执行
{
if (i == input) //当i等于input时停止打印
{
break;
}
printf("%d ", i); //打印 i
i = i + 1;
}
return 0;
}
(输入11i永远不可能等于input,正常打印1-10)
-
输入:11
-
结果:1 2 3 4 5 6 7 8 9 10
(输入6使程序只打印1-5的数)
-
输入:6
-
结果:1 2 3 4 5
让我们来分析一下这个代码。
上例中我们设置 while 循环的表达式为i < 11,又在循环内的末尾让 i 随每一次循环的结束而加 1,易知 i 能使循环成立的最大值为 10,所以当我们想正常打印 1~10 的数时,只需要输入一个大于 10 的数就可以了,如上例第一次输入的 11;当我们想打印 1~5 的数时,我们需要注意,我们的 if 判断语句是写在打印之前的,也就代表当 i 等于 input 时,这次循环中的 i 是不会打印的,所以我们的输入值需要目标数加 1 才能打印,这里目标数是 5 ,那么打印从 1 到 5 的数,需要输入值为 6 。
在这里给大家出个题,如果我们把 break 换成 continue,再输入相同的输入值 11 和 6 又是什么答案呢?可以在评论区留言写出你的答案。作为程序员,我们一定要学会自己动手操作去找出答案,这样才能随着一次又一次的解决问题,提高我们的各方面能力,如信息检索能力、编程能力。
2.2 for循环
for 循环是上面三种循环语句中最常用,最普适的一种循环语句,我们来看看它的语法示例:
for (表达式1; 表达式2; 表达式3;)
{
语句
} //相同的,单个语句也是可以直接跟在for语句后面的,但是,打咩,这不利于程序的可读性和扩展性
其中:
-
表达式1用于循环变量的初始化,如int i = 0,且循环变量的初始化只执行一次。
-
表达式2用于循环条件的判断,如i < 10,如果表达式2结果为0,循环结束,否则继续。
-
表达式3用于循环变量的调整,如i++ 或 i+=2。
-
循环变量的初始化和循环条件一起决定了循环变量的范围,在此基础上,调整则影响了循环次数。
我们来看看执行流程:
我在这祭出一套代码来给大家来分析一下 for 循环的执行流程,如下:
要求打印一个腰长为10的等腰直角三角形,如下图所示。
#include<stdio.h>
int main() //和if嵌套类似,套娃式写法,我们阅读时只需要层层剖析,很容易理解
{
for (int i = 0; i < 10; i++) //外循环,此处含义:i代表第i+1行,一次循环为一行,逐行打印
{
/*内循环,此处含义:j的取值范围代表星号*个数,j随内循循环次数增加而增加,但j的范围即
星号个数随外循环次数增加而减少*/
for (int j = 0; j < 10 - i; j++)
{
printf("* ");
}
printf("\n"); //每次循环结束,即行尾打印一个换行符
}
return 0;
}
我们可以看到,无论是外循环还是内循环都执行了一次循环变量的初始化,往后都是表达式2(循环判断)——语句(循环体)——表达式3(变量的调整)的循环往复,而一旦表达式2的结果为0,循环结束。
2.3 do_while循环
do while 循环是上述三种循环语句中使用最少的,但在某些情况下,它也很有用(Tips:其实 goto 语句也可以实现循环结构,但万一使用不当,后果很严重,有兴趣的可以去了解一下)。下面我们来看看它的语法结构:
do
{
语句;
} while(表达式);
while 和 for 这两种循环都是先判断,条件如果满⾜就进⼊循环,执⾏循环语句,一旦不满⾜就跳出循环;
⽽ do while 循环则是先进⼊循环体,执⾏循环语句,再执⾏判断表达式,表
达式为真,就会进⾏下⼀次循环,表达式为假,则不再继续循环。
其执行流程如下:
在 do_while 语句中,我们通常在循环体外进行循环变量的初始化,当程序执行到 do_while 语句时,先进入循环体执行语句并进行循环变量的调整,一次循环结束后再来执行表达式,判断是否进入下一次循环,所以 do_while 循环是至少执行一次的,这是它的特殊所在。
代码示例如下:
#include <stdio.h>
int main() //打印1-10的数
{
int i = 1; //循环变量的初始化
do //开始循环
{
printf("%d ", i); //循环体/语句
i = i + 1; //循环变量的调整
}while(i < 11); //判断条件:当i >= 11,终止循环,不再打印
return 0;
}
结果:
3.案例解析——猜字谜游戏
到这里我们已经学完了顺序结构,分支结构和循环结构了,除开一点点点点点点点点琐碎的知识外,我们已经可以开始尝试完成一个猜字谜游戏了。
在这里,我们先给出完整代码(有需要自取,无需要可跳过看详解):
#include<stdio.h>
#include<windows.h>
#include<stdlib.h> //提供rand函数,功能为基于某个数(种子)生成随机数;srand函数改变种子
#include<time.h> //提供time函数,用于获取一个时间戳,以时间作为种子
void menu() //菜单函数,提供菜单功能
{
printf("**************\n");
printf("****1.Play****\n");
printf("****0.Exit****\n");
printf("**************\n");
}
void game() //game函数,提供游戏功能
{
//times规定并记录游戏次数,guess存储用户的输入值,r为随机数且此处被赋值范围为1~100
int times = 5, guess = 0, r = rand() % 100 + 1;
while (times)
{
scanf("%d", &guess);
if (guess > r)
{
printf("太可惜了,你猜大了!\n");
}
else if (guess < r)
{
printf("太可惜了,你猜小了!\n");
}
else
{
printf("芜湖~,恭喜你猜对了!!!\n");
break;
}
times--;
if (guess > r || guess < r) //打印剩余猜测次数
{
printf("你只剩下%d次机会啦!\n", times);
}
}
if (times == 0) //一轮游戏结束,打印正确答案
{
printf("\n猜错了哦,正确答案应该是%d\n", r);
}
}
int main()
{
printf("哼哼( ̄、 ̄),大笨蛋赶快看清楚本大爷的名字,本大爷叫作“猜数字游戏”,你应该知道怎么玩。\n");
int input = 0; //存储输入值,用于开始游戏或结束游戏
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
system("cls"); //系统命令:清屏
if (input == 1)
{
printf("\n开始游戏噜!!!赶快输入你猜的数字吧:\n");
}
switch (input) //代码核心部分
{
case 1: game(); break;
case 0: printf("\n游戏结束了,下次再来吧\\(n.n)/Bye~\n"); break;
default: printf("输入错误,请重新输入\n"); break;
}
} while (input);
return 0;
}
下面我们按程序思维来逐步分析:
首先从main函数起始:
int main() //程序入口
{
printf("哼哼( ̄、 ̄),大笨蛋赶快看清楚本大爷的名字,本大爷叫作“猜数字游戏”,你应该知道怎么玩。\n"); //小小的游戏说明,也可写入菜单函数,亦可与菜单函数结合并制作跳转游戏说明页面功能
int input = 0; //存储用户输入值,即0或1,开始或结束游戏
srand((unsigned int)time(NULL)); //使用time函数获取时间戳,强制转换返回值为无符号整型,再用srand函数生成种子
do //用do_while循环先开始,若用户输入1则继续循环,开始游戏,输入0则终止循环,程序结束
{
menu(); //走来先给个菜单
printf("请选择:>");
scanf("%d", &input);
system("cls"); //系统命令:清屏
if (input == 1) //增加一点氛围感
{
printf("\n开始游戏噜!!!赶快输入你猜的数字吧:\n");
}
switch (input) //游戏主体模块,一个小小的分支结构
{
case 1: game(); break; //input为1则跳转到game函数,game函数结束并返回,直接break出去
case 0: printf("\n游戏结束了,下次再来吧\\(n.n)/Bye~\n"); break;//input为0,直接break然后say good bye
default: printf("输入错误,请重新输入\n"); break; //输入错误,但input不为0,直接break出switch语句再循环一遍
}
} while (input);
return 0;
}
main 函数可分为三个核心步骤:菜单函数 —> scanf —> 选择与分支(三个分支:开始游戏、结束游戏、选择错误)。
游戏的开始,我们需要给出一个菜单。我们可以先写一个简单的菜单函数 menu(这里涉及函数知识,可以不用管,按照示例代码写即可)。
void menu() //菜单函数,提供菜单功能
{
printf("**************\n");
printf("****1.Play****\n");
printf("****0.Exit****\n");
printf("**************\n");
}
下一个环节,我们需要一个scanf,玩家借此输入不同值;第三个环节开始之前,我们可以先使用 system(“cls”) 清屏保持游戏画面清爽。注意!!!在第三个环节,我们需要考虑玩家在第二个环节输入错误的可能,我们可以增加一个循环,再走一遍流程,即从 menu—>输入—>分支。
细分下去考虑 input 可能有的三种输入情况,我们先用 switch 来设计一个多分支结构:case 1、case 0和default。接着,我们知道 case 1 需要设计一个具有游戏功能的函数,case 2 需要一个结束语,default 需要一个错误提醒,并且此处不能有分支重叠,所以都要加个 break 来直接结束 switch 语句。
上述,我们在考虑第二、第三环节时说要增加一个循环体,那么对于循环体内设计完毕后,我们需要考虑构建一个什么循环更加方便。很明显,我们可以发现我们设置的输入值正好是 0 和 1(这当然是设计人故意设计包含了一个 0),而其他输入值包括 1 在内都是非零值,我们正好可以用 0 当作跳出循环的条件来设计循环体,很快地,我们的 do_while 循环就派上了用场。
以上是 main 函数的设计流程,我们只需要继续细化,完成我们的重中之重——game 函数,属于我们的一款游戏就新鲜出炉了。
代码如下:
void game() //game函数,提供游戏功能
{
//times规定并记录游戏次数,guess存储用户的输入值,r为随机数且此处被赋值范围为1~100
int times = 5, guess = 0, r = rand() % 100 + 1;
while (times)
{ //当times减小到 0停止循环,一轮游戏结束
scanf("%d", &guess);
if (guess > r) //if else语句用于判断是否猜中数字
{
printf("太可惜了,你猜大了!\n");
}
else if (guess < r)
{
printf("太可惜了,你猜小了!\n");
}
else
{
printf("芜湖~,恭喜你猜对了!!!\n");
break;
} //判断结束处
times--; //调整循环变量
if (guess > r || guess < r) //打印剩余猜测次数
{
printf("你只剩下%d次机会啦!\n", times);
}
} //循环结束处
if (times == 0) //循环结束,即一轮游戏结束,打印正确答案
{
printf("\n猜错了哦,正确答案应该是%d\n", r);
}
}
仔细思考,我们很容易知道,猜字谜游戏玩法的核心设计流程大致如下:输入猜测值—>判断与提示(三个分支 ‘ > ’、‘ == ’、‘ < ’)。很明显这两个流程是一个循环过程,我们还需要一个值来代表循环次数——可猜测次数。我们需要先在循环体外,进行游戏次数 times 和猜测值 guess 的初始化,然后编写循环体,囊括上述两个流程,接着对流程细化,我们需要先 scanf 输入,然后对输入值判断,如果大了就提示玩家大了,小了就提示玩家小了,注意,如果等于,我们就不需要继续猜了,我们直接break终止循环。如果玩家一直没猜中,我们还需要考虑次数耗尽的情况,我们直接告诉玩家正确答案然后结束——game 函数完毕,返回 main 函数继续向下执行语句。
以上就是三大结构的混合案例解析了,如果喜欢我的博客,请直接关注吧~~
我会将我对C语言的理解和认知,精心写下来,这不仅是对我知识的梳理与回顾,更是一种分享,供后来者借鉴(无论妙笔或谬误)与学习,亦给自己一个被先行者校正、勘误和交流的机会。