C 生万物 | 分支和循环语句【内含众多经典案例】

看完上一篇文章,我们对 C 语言要学习的一个整体知识框架有了一个了解,接下去,我们将进入分支和循环语句的学习,Are you ready?
@TOC
一、什么是语句?
- 首先我们来说说什么是语句,在 C 语言中呢,可以将语句分为以下五类 
①表达式语句②函数调用语句③控制语句④复合语句⑤空语句
- 本次我们主要来讲讲==控制语句==,控制语句就是用于控制程序执行的流程,以实现程序的各种结构方式,C 语言是面向过程的,有三种结构方式【顺序结构、选择结构、循环结构】 
- 而上面所说的控制语句在 C 语言中主要是有 9 种,我将其分为以下三类: 
第一类:分支语句【if 语句、switch 语句】第二类:循环语句【do while 语句、while 语句、for 语句】第三类:转向语句【break 语句、goto 语句、continue 语句、return 语句】
说了这么多,接下来让我们先进入分支语句的学习
二、分支语句(选择结构)
1、if 语句
单分支与多分支
有关 if 语句的使用我们在初始 C 语言的时候已经讲过,这里不做过多解释,先来看一下这段代码
- 这里是定义了一个 age 年龄,然后去进行输入,若是输入的年龄 < 18,则打印【未成年】,若是 > 180,那就打印【成年】 
- 具体意思也就是一个判断执行一条语句,满足了这个条件,就进入这个 if 分支执行里面的代码,else 的话就是另一个分支 
- 那有同学问了,难道一个分支只能执行一条语句吗?不可以执行多条? 
- 我们再来看看下面这段代码,可以看到,我在两个 if 分支都加上了{}大括号,这是一个规定,若是你不加上这个大括号,那么这个 if 分支就只会执行一条语句就跳过了 
然后我们再来讲一下多分支结构
- 什么叫多分支结构呢,刚才的话我们是只有 if...else 这两个分支,现在我们的场景不只是【未成年】和【成年】了,而是不同的年龄段为不同的身份,我们来看一下代码 
- 从上述代码可以看出,不同的分支具有不同的结果,而不是像上那样只有 if...else,现在我们输入数据试试看 
...
- 那这个时候有同学问,为什么就可以进入这个分支呢,这个原理是什么? 
- 这就要说到我们的语句执行原理,也就是【真】与【假】 
0 表示假,非 0 表示真
- 那有些学会 C 语言的同学就会想到一个东西【布尔类型】,就是 true/false,这个的话是 C99 里面颁布的,在 C 里面用的还是比较少,C++里面可能多一些,有兴趣的同学可以去研究一下 
悬空 else
但是你真的认为 if...else 就那么容易?我们来看一个东西,叫做【悬空 else】,这是一个大家在书写代码是经常会疏漏的地方:star:
- 首先看下面这段代码,你认为下面会打印出什么内容呢? 
- 首先按照大家的思维理解一下,a 刚开始为 0,所以不会进入第一个分支,而会进入第二个分支,然后打印【haha】,真的是这样吗?我们运行一下试试 
- 可以看到,什么内容都没有被打印,这是为什么呢? 
- 这其实就要讲到我所要说的【悬空 else】,什么是悬空 else 呢,也就是在双层嵌套的 if 语句下,没有加上{}大括号,这个时候 if 分支后的 else 就叫做悬空 else 
- 这个悬空 else 就会产生分歧,到底是和内部的 if 匹配呢,还是和外部的 if 匹配呢?这里也是有规定的,对于悬空的 else,优先和内部的 else 进行一匹配,所以当把我这个代码复制进 VS 编译器时,这个 else 就自动会进行一个缩进,和内部的 if 做一个匹配 
- 所以这就可以印证了为什么没有打印出来任何东西,因为无论是【haha】还是【hehe】,都是处于一个大 if 分支下,而这个大分支的第一层还没有进去,所以程序会直接结束 
- 我们的代码应该改成下面这样 
- 这样的话其实就很清楚了,这个 else 是和内部 if 匹配的,但是其实呢这样也不是很规范,最好是加上{}大括号,才能显得规范一些 
if 书写形式的对比
有关 if 语句的书写也是有讲究的,我们一起来看一下
- 你认为下面两段代码那个是书写规范一些的 
- 答案是第二段,其实它们所要表达的意思都是一样的,这个 condition 就是条件。若是条件成立,则 return x,若是不成立,则 return y 
- 但是为什么说第二段代码更好地,并不是它写得更长一些,而是这个逻辑框架比较清晰,让阅读者看了一目了然 
接下去我们再来看另外两段代码,你认为那段代码比较好一些呢
- 答案也是第二段,那这时候就有同学疑问了【num == 5】是在判断这个 num 值是否为 5,那么把这个 5 放在前面是什么意思呢 
- 这就是说到一个很多程序员都会犯的,也就是把这个判断写成了【num = 5】,变成了一个赋值操作,这其实就会为后期的程序开发买下一个巨大的 Bug,这时你在调 Bug 的时候就会很痛苦,就是找不到哪里有错误,这个时候就去规范我们对于代码的书写 
- 最好是写成【5 == num】,为什么要这样写呢,你看我这个时候将判断等于号改成一个等于号,这个时候编译器就会报错,说【这个表达式必须是可修改的左值】,这其实是正确的,以大家的思维来说,都是讲一个值赋给一个变量,也不会将一个变量给到一个具体的值,也就是【5】这个常量 
- 但程序报出错误的时候程序员就会立马去排错,这个时候也就降低了 Bug 存在的风险 
🔥炙手可热的阶段小训练🔥
学完了 if 语句,接下去让我们来做两道练习题巩固一些所学的知识吧
- 大家可以自己去做一下,这里只给出代码 
1、判断一个数是否为奇数
2. 输出 1-100 之间的奇数
2、switch 语句
讲完了一种分支语句,接下来让我们继续学习下一种分支语句,也就是 switch 语句
- 对于 switch 语句,常常用于多分支的情况,那有同学说,那个多分支不是 if..else 也可以实现吗,那为什么要用这个呢 
- 我们来看看下面这段代码,这是对于星期的一个判断 
- 但是你仔细看,不觉得这样去写这么一个判断很复杂吗,要写这么多 else if,会有些繁琐,接下去我们来学习一下这个【switch 语句】 
- 先来看一些格式 
- 那这个语句项是什么呢? 
好,了解了这些后呢,我们使用【switch 语句】来重写一下前面的那个星期判断
- 今天是星期四,我们来输入 4 运行看看 
- 那这时候有些小伙伴就震惊了,这是什么鬼?我想要的只是星期四而已,但是五、六、天都被输出出来了。这个的话叫做【switch 穿透】,大家不要怕,我们来分析一下:mag: 
break
- 然后我来说一下这是为什么,对于 switch 语句的话,有很多【case】分支,一个语句执行完之后,还是会往下一个语句执行,但是我们希望的是在 case:4 进去,然后打印完了这一句话后便跳出这个判断,不再执行下去了,那这要怎么实现呢? 
- 这时候应该用到一个我们在初始 C 语言里讲到的,叫做 break,到执行到这一个 break 的时候,便会跳出,不会再往下执行了 
我们加上这个 break 后试试
- 可以看到,成功了🎇 
- 但这样子程序还是不完整,我们继续来看看 
default 子句
- 可以看到,我在这个地方输入了一个 8,但是程序什么都没有输出,这是因为 8 没有进入任何一个 switch 分支,所以程序直接结束了。那应该怎么办呀!!! 
- 不要急,这个时候我们应该再增加一个 default 分支,作为默认分支,若是其他 case 子句都没有进入,则会进入这个【default】分支,我们来试试 
- 可以看到,成功了 
- 那这个时候我们换一种思维,当多个条件满足的时候,执行同一个结果,也就是这样的需求 
1、输入 1-5,输出的是“weekday”;2、输入 6-7,输出“weekend”
- 我们来实现一下代码 
<font color = "#ff0000">注意事项:break 千万别忘了,很重要,不然会穿透的</font>
📰强大的面试题📰
以下是一道面试题,我们一起来看看
- 你认为下面会输出多少呢❓ 
- Are you Right? Let's analyze it. 
- 看完我下面这一段实时分析,你就会懂了 
三、循环语句
好,讲完了这个分支语句后呢,我们来说一说 C 语言中的循环语句
1、while 循环
- 看到下面的代码,我们 if 的判断改成 while 就构成了最基本的 while 循环 
- 然后就是我们在初始 C 语言中就讲到过的通过循环来打印 1~10 的数字,在 while 循环内部控制变量的循环条件,若是满足,则一直循环,直到这个循环变量超过边界为止 
while 语句中的 break 和 continue
对于 break 和 continue,我们之前在分支判断中也有提到过,那在循环中是怎样的呢,我们来看一下
- 你认为下面这段代码会打印什么内容。break 的话停止后期的所有的循环,直接终止循环 
- 可以看到,因为当 i 循环到 5 的时候,遇到了 break,因此跳出了整个 while 循环,不会执行下面的 printf 打印语句以及 i++了,所以只会打印到 4 
- 然后我们再来看看 continue 
- 对于 continue 的话,是终止本次循环,强制进入下一次循环 
- 可以看到这个光标的值,停留在 4 的后面不动了,这是为什么呢? 
- 我们来分析一下 
- 可以看到,这其实是一个死循环,当 i 加到 5 的时候,由于进入了 continue,所以 i 不会进行一个递增,继而导致了这个死循环 
- 那这个代码应该怎么改才不会死循环呢?对,就是把这个 i++放到 if 判断的前面 
- 看完了【break】和【continue】,接下去我们来总结一下 
<font color = "#ff0000">continue - >>某种条件成立时跳过后面的代码</font><font color = "#ff0000">break - >>某种条件成立时整个循环不执行</font>
getchar()的巧妙运用
讲到 while 循环,我们来说说【getchar()】这个库函数的使用
- 上述图是运行结果以及cplusplus的资料 
- 对于 getchar()的话是对键盘读入一个字符,然后可以通过 putchar()输出。要注意到,这个 getchar()的返回值是 int,这个我们下面会讲到 
这个时候有同学问了,这个 getchar()和 while 循环有什么关系呢?
- 我们来看看下面这段代码 
- 从运行结果可以看到,使用 while 循环,每当我们输入一行数据,知道按下回车,putchar()会将这一行数据原封不动地打印出来 
- 这里的【EOF】指的就是【End Of File】文件末尾的,循环的意思是==当这个输入没有到达文件末尾时,getchar()就会从键盘上不断地去读取数据,直到文件末尾即要换行为止== 
那这个时候又有同学说,这个 getchar()很厉害呀,竟然可以读一串数据
- 但其实这个 getchar()的使用是存在缺陷的,我们一起来看看 
- 这是一段确认密码的程序 
- 可以看到,我在输入完密码然后换行后,但是还没有去确认密码,但是程序直接结束了,说【确认失败】,这是为什么呢?这个 getchar()到底有没有执行? 
- 我们来看一下==计算机内部缓冲区读取数据的原理== 
- 从这张原理图可以很清楚地看出,scanf 会从键盘上读取一些你输入的数据,但你不输入的时候,它就一直等,一直等,直等到你输入为止。 
- 但是这个 scanf 不会直接去取你这个键盘上输入的数据,在计算机中呢,是存在一个输入缓冲区的,但我们把这个数据从键盘上输入进去的时候,会先进入缓冲区,当我这个 123456 输入进去后,为了让数据进入到缓冲区,我还敲了一个回车,表示这个输入结束 
- 然后 scanf 进来到缓冲区看了,有没有数据我可以读的,这时候它看到有数据,它就读,直到读到\n 为止。然后将这个数据给到 password 作为密码;此时 getchar()也来读数据了,这个 getchar()的工作原理其实和 scanf()是一样的,就看缓冲区里有没有东西,然后看到,哟,有个【\n】,于是读取了这个数据,把它放到 ch 里面去了,那接着就去判断这个 ch 为‘Y’吗,很明显不为‘Y’,所以就进入了 else,打印了【确认失败】,==这就是编译器没有等我们输入确认密码就直接结束程序的原因== 
你明白了吗?
2、for 循环
语法明细
看完了 while 循环,接下去我们来看看 for 循环,对于 for 循环大家一定不陌生,它是使用最多的循环语句
- 那有同学问了,我们既然已经有这个 while 循环了,为什么还要 for 循环呢,让我们先来看一下 for 循环的语法 
- 表达式 1 为初始化部分,用于初始化循环变量的 
- 表达式 2 为条件判断部分,用于判断循环时候终止 
- 表达式 3 为调整部分,用于循环条件的调整 
- 可以看到,for 循环不像 while 循环那样,将三个表达式分散在整个程序的各处,对于 for 循环的话都是放在这一个小括号里进行,每个表达式使用分号进行分隔 
- 就像我们这里去打印 1-10 的数字,使用 for 循环的话就会很清晰直观,代码也比较简练 
- 可以看到,一样是可以打印出来 
for 循环中的 break 和 continue
在 while 循环中,我们有详细讲到过 break 和 continue,但是在 for 循环中是如何使用的呢?我们一起来看看
- 首先来看 break,很清晰直观,循环从 1 开始,循环的边界是到 10,i++进行一个递增,也就是 i 加到 11 的时候会跳出这个 for 循环,然后看循环体内部,当循环进入时若判断这个【i == 5】时,则执行 break 语句跳出循环;若没有到达 5,则会打印这个 i 
- 然后我们再来看 continue 
- 从运行结果可以看到,为什么这次在 for 循环中直接打印会输出 1234,然后 678910 呢,而不是像 while 循环那样在 4 的地方终止,然后死循环,这就是因为这个 i++是 for 循环每次进入的时候就会执行,就和我们在 while 循环中把 i++放到上面来是一个道理 
- 对于这点,我们在下一个模块来详细讲一下==for 的执行流程== 
执行流程解释
- 但是初次接触这个 for 循环的同学一定对这个循环的执行流程有所困惑,因为对于 while 循环的话,代码虽然是写得比较散,但是却很好理解,for 循环就会显得堆在一起的感觉 
- 我们一起来看一下这个执行流程到底是怎样的 
- 从上图可以看出循环进入时,首先执行第一个表达式,也就是初始化部分,然后在进行条件判断,若是不为 0,则继续执行下面的循环体语句,执行好后又来到表达式 3【expr3】,调整循环变量后继续 
- 若是这个条件判断依旧【! = 0】,此时会继续进入循环,然后直到条件循环为 0 为止,才会结束循环 
- 然后可以看到图中还有这个【continue】和【break】,对于 continue 来说呢,就是跳出本次的循环,不执行下面的循环体语句了,直接回到循环体开头对循环变量进行调整;而对于 break 呢,可以看到,直接来到了这个【expr1 == 0】这条支路,说明会直接结束循环的运行 
📕多学几招📕
接下去给大家讲讲在 for 循环使用时的一些注意事项和一些技巧
- 你认为下面这段代码的执行结果是什么 
- 可以看到,【满屏的 666】 
- 如果大家觉得我讲到好的话,在弹幕上扣一波【666】,不过 CSDN 的文章里没有这个功能,但是你可以在评论区扣(doge) 
- 好,言归正传,为什么这个直接结果会都是 666,但是你自己观察可以发现,第一个打印的是 1,这个时候你就可以根据我上面的 for 循环流程图,将这个 
3、do...while 循环
讲完了 while、for,接下去让我们来看看 do...while 循环,这也是循环语句的一种,只是在各个应用场景中没有 while 和 for 来得广泛
语法介绍及案例分析
- 首先来看一下它的语法格式,和 while 循环很类似 
- 然后再来说一下其特点,因为 do...while 循环在执行到时一定会进入循环体,然后再进行一个判断看看是否要继续执行。但是对于大多数使用循环的场景,都是需要先进行一个判断,然后在执行一个循环,所以这就让 do...while 的使用场景变得十分有限 
我们先来一个具体的小案例
- 业务逻辑是需要使用 do...while 循环去打印 1~10 的数字,这个逻辑的话我们在 while 循环和 for 循环都有实现过 
- 刚才说过,对于 do...while 循环,遍历到的时候会直接进入循环体,这里会打印 i 然后 i++,判断 i【i == 2】,所以继续执行循环,直到这个 i 加到 11 的时候便不再进入循环,结束程序的运行 
do...while 中的 break 和 continue
对于 break 和 continue 这两个关键字,也是从本文的开始就一直陪伴我们,让我们到 do...while 中来看看它们要如何使用
break
- 可以看到,其实和 while 循环是相似的,也是当 i 为 5 的时候终止循环 
continue
- 可以看到,对于 continue 也是一样,若是这个 i++在 continue 语句的后面,则在 continue 语句执行到的时候,就会强制进入下一循环,那么这个 i 便一直会是 5 了,始终不会被打印出来,就造成了死循环 
四、实战小训练
1、 计算 n 的阶乘
首先第一题比较简单,计算一个 n 的阶乘,那只要定义一个变量去存放这个阶乘的结果,然后通过循环去遍历即可
- 这里要注意,ret 初始要置为 1,否则在任何数和 0 相乘必定为 0 
2、 计算 1!+2!+3!+……+10!
第二小题又是一道计算阶乘的题,不过这题计算的阶乘不是单个的,而是计算一个累加阶乘的和,我们一起来看看
- 假设我们是要计算 1! + 2! + 3!,数字小一些。首先来分析一下思路,因为要计算的数字只到 3,所以我们需要一个外层循环从 1 遍历到 3,表示求解的是这 3 个数的阶乘 
- 然后内层循环就是每一个数的阶乘求解,从 1 遍历到这个数即可,然后使用一个累乘变量存放起来。在计算完每一个数字的阶乘后,我们就需要去累加这些阶乘的和,所以还需要定义一个 sum 变量去存放这个和,最后 sum 变量就是我们所要求的结果 
- 正确答案应该是 1 + 2 + 6 = 9,我们通过 VS 来跑一下看看 
- 可以看到,sum 的结果并不是 9,多了。这是为什么呢? 
- 这里其实就是很多通过都会犯的错误,因为我们是在求解不同数字的阶乘,但是使用的累乘变量却是同一个 ret,所以下一个数字需要计算的时候,这个 ret 还是上一次数字累乘后的结果,这就导致了阶乘计算的不准确,所以结果也会不同 
- 具体的错误大家可以自己去 DeBug 试一试,是这个 3!在计算的时候多乘了一个 2!遗留下来的 2,所以使得 3!= 12,多了 6,因此最终结果也就多了 6 
- 应该加上这句话才对,在每一次更新需要求阶乘的数时,都将这个累乘变量 ret 重置 
- 其实还有一种更加方便的方法,使用一次循环就可以把结果计算出来,具体的演示过程已经给出,大家自己分析一下即可 
3、 在一个有序数组中查找具体的某个数字 n【讲解二分查找】
然后就是这道在个有序数组中查找具体的某个数字 n
- 那有同学一看到要在一个数组中查找一个数字,就想到去遍历这个数组,这个逻辑是对的,但是不够巧妙,我们需要更加巧妙一点的办法去解决这个问题 
- 这里介绍一个查找方法,叫做==二分查找==,什么叫二分查找呢?就是在一个数组的左右两段各定义一个指针,然后取它们的中间值,然后将你要查找的数字与这个中间值进行比较,若是比中间值要小,那么就去除掉后面那一部分区间,只需要找前面就可以了,若是比中间值要大,则去除掉前面那一部分区间,找后面。将这个逻辑放到一个循环中,不断地去更新中间值,然后做比较,最后左右两段的指针会重合,表示这个区间快要结束了,若是当左指针大于右指针时,也就意味着已经查找到所需要的元素或者是没有找到,此时便要退出循环进行一个相对的打印说明 
- 讲完了这一块的逻辑后,我们来看一下具体的代码 
- 具体的讲解我就不说了,你们可看我的另一篇文章,做了详细介绍二分法与折半插入排序 
4、编写代码,演示多个字符从两端移动,向中间汇聚【微信手机端看不到视频】
然后我们来玩一个很有趣的东西,将多个字符从两端移动,向中间汇聚
- 我们来看一下,演示多个字符从两端移动向中间汇聚,我们需要实现一个覆盖的效果,比如我下面定义了两个数组,我们最终需要打印出来的效果是第一个数组的内容,但是在打印过程中我们需要打印第一个数组,然后也是通过两段左右指针去进行一个覆盖的效果 
- 首先是对于左右指针的初始化,左指针就是 0,但是对于右指针的话,这里取不到它的末尾值,所以这个时候我们需要使用到 strlen()这个库函数去求解数组 1 的长度,然后-1 就是右指针的位置 
- 我们也是将这个逻辑放到一个循环中,然后把第一个数组的内容通过两个左右指针赋给第二个数组,然后这两个指针不断往中间移动,直至左指针大于右指针为止 
- 这里为了让其慢慢地显示出来,呈现一个动画的效果,又使用到了一个库函数,也就是 Sleep()睡眠函数,这个函数还是蛮有意思的,参数的话你需要传入毫秒值,比如说 1s 执行一个就传入 1000,0.5 执行一下就传入 500。还有这个函数需要引入头文件【#include <Windows.h>】,大家记得加上哦 
- 然后我们通过运行结果来看看这个效果是怎样 
[video(video-JUqwkuMS-1666671841689)(type-csdn)(url-https://live.csdn.net/v/embed/247980)(image-https://video-community.csdnimg.cn/vod-84deb4/eb50040f2835448ba6dad09d0382ed32/snapshots/ca1a0d18a916465fb39ff11274cfe2e3-00001.jpg?auth_key=4820212508-0-0-ce3c6bccf52d912ef9a3f83b65b96cfc)(title-QQ录屏 20221024174502)]
为了让其在一行打印,不需要一行行地打印,我们可以使用这样一个命令
- 但是这个 system()函数要加上头文件【#include <stdlib.h>】,大家不要忘了。我们加上这条语句后再来看看运行效果是怎样的 
[video(video-Q24mZ0io-1666671888836)(type-csdn)(url-https://live.csdn.net/v/embed/247982)(image-https://video-community.csdnimg.cn/vod-84deb4/34e4bd79021942348ed09b3b0de4a343/snapshots/7c8bb45bbd40414c9649054fe16d1990-00001.jpg?auth_key=4820217046-0-0-2b87b46aaedb5f32dd4773bfb9c60369)(title-两端移动)]
5、密码校验
这道题的话就是我们输入一串字符,然后通过与正确密码进行一个比较,看看是否相同,若是相同,则直接 break 跳出循环,若是不同则继续输入,但是机会只有 3 次,用完之后便跳出循环不允许再输入了
- 实现逻辑并不难,你可以先自己写写看,检验一下自己学得怎么样,然后再来和我的程序进行一个比较 
- 这里要注意的一个地方是有挂字符串比较的问题,我们不可以直接使用【==】去进行一个比较,而是要通过一个字符串的库函数 strcmp 进行比较。有关其返回值的问题,我们通过Cplusplus来看看 
- 也就是当这个第一个字符串的首字母大于第二个字符串的首字母时,就返回大于 0 的数字,小于 0 则是相反,若是两个字符串相同,则返回 0。这里比较的是 ASCLL 码值的大小 
6、猜数字游戏【经典】
好,接下来我们来玩一个 C 语言中很经典的游戏,叫做==猜数字==
- 首先我们来实现一个整体的逻辑,也就是当你 input 输入的时候,通过我们上面学习的 switch 语句进行一个分支的判断,是要继续猜数字还是退出游戏 
- 一起先来看一下代码,首先你要有一个菜单供玩家去选择 
- 可以看到,整体的逻辑已经实现了让你按下【1】的时候,会实现一个猜数字的功能,若是一直按 1,则可以一直猜数字,直到你按下 0 为止就可以 
- 接下我们就要实现猜数字的内部游戏逻辑,这个逻辑其实也是非常简单,通过系统随机生成一个数字,然后你在屏幕上去输入这个数字去猜,若是比这个数大,则提示数字大了;若是比这个数小,则提示数字小了,然后直到你刚好猜中为止 
首先我们来讲讲这个随机数是如何生成的
- 这就要用到 C 语言中的一个函数叫做 rand(),你可以在 Cplusplus 中找找看这个,可以看到,这是一个生成随机数的函数,参数是空参。它的范围是【0~32767】 
- 但是我们要实现的是随机生成一个 1~100 之间的数字,这个时候你就需要在这个函数后面对 100 进行取余即可,就是【0-99】之间的数字,再在后面加上一个 1,就是【1-100】 
- 我们通过 printf 来打印一下,看看系统生成了那些随机数 
- 可以看到,在一次游戏的过程中,数字是不一样的,但是在第二次又打开时,确实和第一次相等的随机数,这就出现了问题,你要想若是玩家碰到了这样的情况,每次都是相同的数字,它还会继续玩下去吗,当然这只是打个比方:camera: 
- 那我们要怎么去解决这个问题呢?这个时候我们就要使用到一个 C 语言中的另一个函数叫做随机种子 srand(),我们通过 Cplusplus 再来看看 
- 但是呢,光有这个函数还不够,一般还要再配合使用一个时间戳函数 time() 
- 直接让你看看具体是如何使用的 
- 我们来分析一下,首先看到这个 time()函数,里面的参数设置了 NULL 为空,然后前面为什么要强转成(unsigned int)呢,因为这个 srand()函数的参数类型就是(unsigned int),所以需要进行一个强转 
- 这句话大家要记得加在游戏循环的外面,因为这个随机种子最好是不要多次使用,用一次就可以了,多次使用的话会导致一些错误,所以将其放在 main 函数开头的位置即可 
- 还有一点不要忘了,这个 time()函数是要包含头文件的【#include <time.h>】 
- 我们加上这句话后再来看看两次打开游戏的运行结果是怎么样的 
- 可以看到,产生了这个随机的效果 
- 好,后面我们就要来真正地实现这个猜数字的逻辑了,直接让你看看代码就会了:wind_chime: 
- 对了,记得把这个随机生成的打印数字去掉,不然你就看到答案了 
- 我们来看看运行结果。可以看到,整体的整个简易逻辑已经得到了实现,你可以自己到编译器中试试看:computer: 
五、goto 语句【了解即可】
接下去我们来说说 goto 语句,对于 goto 语句,开头有提到过,是属于转向语句的一种,其余的还有 break、continue 和 return 语句上面在讲分支和循环语句的时候都已经有涉及到了
- 我们直接来看一个小案例,这里是在一个输出语句 printf 的后面加了一个 goto 语句,然后执行这个 goto 语句的话会跳到输出语句的前面, 然后继续执行下面的代码,这里要注意,【跳转的地方变量后面是要使用冒号的!!!】 
- 然后我们来看一下运行结果 
- 可以看到,上面是输出了很多的【hehe】,表明这已经进入了一个死循环了,当然这只是一个小案例,让你了解一下 goto 语句的执行流程,平常写代码可不能这么去写 
- 然后我们再来看一个,下面这段代码的意思是在打印完一个【hehe】语句的时候,执行一个 goto 语句,然后会直接跳转到下一个【heihei】语句,并不会执行【haha】语句 
- 真的会是这样吗,让我们一起来看一下结果 
- 可以看到,【haha】语句并没有被执行,这也印证了我们的猜想 
- 以上就是 goto 语句的一些基本用法就,大家了解一下即可,不用去过度深究,因为对于 goto 语句的话其实在某些地方使用是不太好的,因为程序是一行行执行的,若是进行了一个跳转的话就会导致整个程序的逻辑混乱,所以还是不太建议大家去使用这个语句 
- 一般的 goto 语句真正适合运用的地方其实是==多层嵌套循环的地方==,可以节省 break 子句的频繁使用,只需要一次 goto 即可跳出循环。 
虽然 goto 语句不为广为使用,但是上面说过了,在某些场合下还是可以派的上用场的,下面我们来说一个使用 goto 语句的经典案例
- 下面这段程序很有趣,是网上的一个段子改编的,使用 system()函数调用一个 60s 后关机程序,然后输入【***】,若是和它要你输入的内容一直,就取消关机程序,若是不一致,则使用 goto 语句继续跳转回来,直到你输入的内容是它要的内容为止 
- 哈哈,看了这个输入内容确实是很有趣,大家下去可以自己试试看,是不是真的会关机【记得保存包文件哦 doge】 
- 不过这段逻辑还可以使用 while 循环实现,然后符合规则的话就 break 跳出即可 
六、总结与提炼
- 在本文中,我们学习了分支和循环语句,在分支语句中,我们学到了【if...else】和【if...elseif】分支判断,以及 switch 语句中 case 和 default 子句的使用。在循环语句中,我们学到了 while 循环、for 循环、以及 do...while 循环,并且观察了 break 和 continue 子句在上述分支和循环子句中的具体使用和注意事项 
- 后期阶段,我们还通过了 5 个实战小训练,对这些知识点有了一个很好的回顾和消化,让大家对分支和循环语句的了解更加深刻 
- 在最后,我们又介绍了一个跳转语句 goto,不过除了在多循环嵌套的情况下其他地方不建议使用 
以上就是本文所要讲的所有内容,感谢您的观看,如有疑问请于评论区留言或私信我:rose:
版权声明: 本文为 InfoQ 作者【Fire_Shield】的原创文章。
原文链接:【http://xie.infoq.cn/article/ed9e275ac3c0e73bb1c158727】。文章转载请联系作者。

 
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
 









 
    
评论