特别注意:
本篇博客承接chapter4——分支与循环上的内容,第一次点进来的的小伙伴可以跳到结尾找到我创建的专栏进行阅读哦
那么废话不多说,直接开始我们今天的内容
一.do while循环
1.语法形式
do while 与 while 和for 语句有一个差别,
那就是while和for这两种循环都是先判断,当条件满足时再进入循环,执行语句,如果不满足就跳出循环
而do while循环则是先直接进入循环体,执行循环语句,然后再执行while后的表达式,如果表达式
为真再进行下一次,为假则不再继续循环
2.实例练习
下面我们来看一个具体的实例来理解一下这个循环语句
题目一:请运用do while语句在屏幕上打印 1-10的值
参考代码如下
题目二:
输入一个正整数,判断这个正整数有几位数?(使用今天学的do while 语句)
eg. 输入:1234 输出:4
提示:判断一个正整数有几位数,我们可以利用下面的这个思想:
请看,数字1234被整除一次变成123,再除一次变成12,再除一次变成1,再除一次变成0, 一共除了四次,那么这个除的次数是不是正好等于它的位数?嘿嘿,看到这大家应该知道怎 么去写了吧,不过要注意一下判断的条件去调整语句的顺序,控制好边界
参考代码如下
二.break和continue语句
1.while循环中的break和continue
关于break,其实如果有细心的同学会发现,前面我们学习switch语句的时候就用到过它,那么今天我们会详细讲到它的用法
首先,与上面do while的练习题目一样,我们先使用while语句打印1-10的数字
如果我们在这个while循环中引入break,请大家看一下下面的代码,并预测一下运行的结果
结果如下
这里当 i = 5的时候执行了break语句,循环就终止了
这下大家就知道这个break的用法了吧
它的作用是永久的终止循环,只要 break 语句被执行, break 外的第一层循环就被终止了(注意:在多重循环中它只能终止离它最近的那层哦)
那看完了while循环的break,我们再来看一下continue在while循环的作用吧
continue 是继续的意思,在循环中的作用就是跳过本次循环中 continue 后边的代码,继续进行下一次循环的判断
同样是上面的那道题,如果把 break 换成 continue 会是什么结果呢?
是打印出1-10中除了5的数吗?
我们来看下面代码的结果
大家可以发现结果4后面的光标一直在闪,这是为什么呢?为什么结果不是打印出1-10中除了5的数呢?
那是因为这里跳过了i = i+1,所以i⼀直为5,程序陷入了死循环
那么,到这我们就能分析出来, continue 可以帮助我们跳过某一次循环 continue 后边的代码,直接到循环的判断部分,进行下一次循环的判断,
而如果循环的调整是在 continue 后边的话,可能会造成死循环
2.for循环中的break和continue
当我们了解了break和continue在while中的用法,我们应该学会举一反三去得出在for循环中它俩的作用
请看 下面的代码示例,去感受break在for循环的用法
其实它在while循环与在for循环中作为终止循环的作用是一致的,对吧
那我们把上面的代码中的break换成continue,结果又会怎么样呢
因为这里的循环的调整不是在 continue 后面
这里我们执行continue语句后跳过了在语句块中它后面的语句来到的循环的调整部分,所以这次没有陷入死循环,而是打印了1-10中除了5的数
其实作用与while是一致的,对吧,所以我们要学会这种举一反三的思想,这将会大大简化我们学习的难度
那下面我们用一张图来对比一下两个continue的区别
3.do while循环中的break和continue
关于do while循环的break和continue,我们直接上代码,留给大家去感受,这也是一个举一反三的过程,值得注意的是 do while 与 while 和for 语句有一个差别,
那就是while和for这两种循环都是先判断,当条件满足时再进入循环,执行语句,如果不满足就跳出循环
而do while循环则是先直接进入循环体,执行循环语句,然后再执行while后的表达式,如果表达式
为真再进行下一次,为假则不再继续循环
这个我们在上面也有讲过,那么下面是代码的示例
通过一个多章节的学习,至此,我们学习完了循环的三种语句,while for 和 do while 以及在语句中会用到的break和continue语句(鼓掌鼓掌)
接下来,我们来看看循环的嵌套,即将上面学到的知识进行一个融合
废话不多说,我们开始吧!
三.循环的嵌套
关于嵌套,我们就直接上练习
题目:找出100~200之间的素数,并打印在屏幕上
解析:
1. 要从100~200之间找出素数,我们首先得先产生100~200之间的数
2. 假设要判断i是否为素数,需要拿2~i-1之间的数字去试除i,需要产生2~i-1之间的数字
3. 如果2~i-1之间有数字能整除i, 则 i 不是素数,如果都不能整除,则 i 是素数
大家可以先写,并在编译器上运行,写完了也可以看看下面的参考代码以及结果,看自己有没有写对
四.goto语句
goto 语句可以实现在同一个函数内跳转到设置好的标号处
是C语言中非常特别的语法之一
我们可以看到,使用goto语句后,它跳过了原来要打印的二,直接来到了next:后面的三
其实goto语句看上去跳来跳去的很方便,但其实我们实际使用的机会并不多,因为它会打断正常的程序执行流程,所以我们建议能不使用就尽量不使用
不过goto语句也不是一无是处,
例如:在多层循环的代码中,如果想快速跳出 那么使用goto语句就会非常方便了
五.猜数字游戏
我们在掌握了上面学过的知识之后,现在我们来写一个小游戏:猜数字
1.设计游戏
关于这个小游戏的策划
Game rule:
1. 电脑自动生成1~100的随机数
2. 玩家猜数字,猜数字的过程中,根据猜测数据的大小给出大了或小了的反馈,直到猜对,游戏结束
那在正式开始做游戏的核心:生成随机数与猜数字前,我们先把程序的框架打好
请看下面的代码
下面是运行的结果
大家看,我们是不是这样就把游戏的框架搭好了,我们做了游戏的菜单,写了选择不同的数字会进入哪条分支的代码,虽然我们还没有具体的实现游戏的主功能,但我们已经对整个项目进行了一个整体的把握
所以我也推荐大家在写代码时尽量先从整体把握,这有利于我们思路的整理
下面我们开始写主功能的代码吧!
2 .Game rule 1 随机数的生成
C语言给我们提供了⼀个函数叫 rand,这函数是可以生成随机数的
它的形式如下
int rand (void);
rand函数会返回⼀个伪随机数(注意我说的,这是一个伪随机数),这个随机数的范围在VS编译器上是0-32767
rand函数的使用需要包含⼀个头文件是:stdlib.h
即我们需要在使用前写上#include <stdlib.h> (这跟我们要使用printf和scanf前要引用
#include<stdio.h> 原理是一样的,是对库函数使用的声明)
那我们就测试一下rand函数,这里我们测试时产生5个随机数看看
这确实是5个随机数,但是如果各位多运行几次这个代码就会发现,不管运行几次,这个随机数都是确定的,这也是我们说rand函数返回的是伪随机数的原因
那么为什么是这个样子呢?
其实rand函数生成的随机数,是通过某种算法生成的随机数。
rand函数是对一个叫种子的基准值进行运算生成的随机数。
之所以每次程序产生的随机数序列是⼀样的,那是因为rand函数生成随机数的默认种子是1。
听起来有点复杂,是吧,不过请记住下面这句话吧
如果要生成不同的随机数,就要让种子是变化的
这时我们就要先引入新的函数叫 srand ,它的形式如下
void srand (unsigned int seed);
我们在调用 rand 函数之前先调用 srand 函数,通过 srand 函数的参数seed(种子)来设置rand函数生成随机数的时候的种子,只要种子在变化,每次生成的随机数序列也就变化起来了
这样子问题好像已经解决了,但其实有一个矛盾点,那就是
给srand的种子是如果是随机的,rand就能生成随机数;
但我们如果要给种子生成随机数,又势必需要生成随机数,这就矛盾了
看到这,可能小伙伴们已经开始抓狂了,整了这么就又绕了回来,BUT
别急,我们还有最后一招,让我们引入本章的最后一个函数 time
首先我来告诉各位我们为什么需要这个time,那是因为啊,时间就是在不停的变化的。
所以将它放在srand函数的参数seed中是一个合适的选择
所以各位先别急,且听我娓娓向您道来这个time函数的用法
time函数的原型如下
time_t time (time_t* timer); 使用前记得引用 #include<time.h> 哦
这里的time_t是它这个函数返回的类型,这个返回的类型也是一个时间戳
那么什么是时间戳呢?
就像生活中的邮戳表示的是邮件什么时候邮寄的
时间戳表示的是一个时间点
返回的是1970年1月1日0时0分0秒到现在程序运行时间之间的差值,它的单位是秒
所以可以认为time_t类型本质上是一个整形类型
ok,接下来我们再来看看括号里的东西,这里涉及到指针。不过这里,因为我们现在不使用time函数的参数,所以我们在里面放上 NULL(空指针)就可以了
好了,讲了这么多,终于可以在代码上运行了,请看下面的代码
这里的time(NULL)就是我们需要的seed种子
因为time本来返回的是 time_t类型所以我们在前面加上(unsigned int )表示强制类型转换
然后我们进行运行,
我们发现程序运行变得随机起来了 (成功!鼓掌鼓掌)
最后我们实现生成1-100的随机数,即设置随机数的范围
方法如下
rand()%100+1
为什么是这样呢?
因为%100的余数是0~99
将0~99的数字+1则范围变为1~100
搞定!
3.Game rule 2 猜数字
ok,搞定了这点,接下来,我们再来写猜数字游戏
先给大家上成品
先不论代码具体的内容,大家有没有觉得在case1:游戏开始 的这个选项的内容特别多,代码看上去不过精简?
所以我建议将这个猜数字的代码与上面的这个游戏菜单的代码进行一个封装
先看我们已经写好的游戏菜单的代码,我们可以这么写
再看一下原来的代码
有没有觉得将这个游戏菜单的代码移出main函数代码更加爽朗?
那么我们怎么去封装呢?
这里的封装其实是自定义函数
形式如下
类型 函数名()
{
}
这里返回的类型是void表示我们不需要返回值,所以也没有写return
下面我们对游戏的猜数字也进行封装吧
这里的逻辑比较简单,我们直接上代码
最后我们将这两个封装的函数与主函数结合起来就写完了我们的猜数字游戏啦
一次游戏的过程
4.一些问题
如果我们把srand((unsigned int)time(NULL));这句代码放在game()这里面的话
生成的随机数会出问题
请看结果
我们发现,生成的随机都是挨着的,甚至如果我们生成的足够快的时候,这个数会是同一个!
这是一个很严重的问题,但是为什么呢?
其实问题就处在我们每次生成随机数时,它的种子都重新设置了,
因为种子是根据time来决定的,当时间变化不大时,种子的变化也不大,那么它的随机数会变得非常非常相似
所以我们用srand设置种子时,在整个程序中只要设置一次就可以了
最后,关于这个代码,其实还可以进一步优化,比如设置猜数的次数等等,这些就留给各位去思考了
至此,这个猜数字游戏的小项目我们就写完了!
结语:
好了今天的分享就到这里了
哦,对了,如果大家觉得博客在哪里需要改正,可以在评论区留言呀,感谢感谢
也希望大家给这个萌新博主点个赞吧(求求)
让我们在接下来的时间里一起成长,一起进步吧!