第19章:循环语句for

19.1 while循环中的初始化、判断和调整

      我们在学 while 循环的时候,我们要感受到一个点,什么点呢?举个例子,要在屏幕上去打印1-10,我们写的是:int i = 1,while(i <= 10),这个时候我们进来,进来之后打印 i,然后 i++如图所示:

      而这个代码里边,我们要注意3个点,这个 i 初始化成多少,会直接影响到我这个代码的结果,比如说 i 写成10,那只打印一个10,结果变了

      为什么呢?因为 i 是10的时候,在 while 循环后边,圆括号里边的表达式≤10只能进去一次,i++变成11就进不去了,如图所示:

      所以 i 是多少,非常重要,这叫初始化,就是我们给这个 i 赋一个初始值是多少,这是非常重要的,如图所示:

      其次,影响到这个循环,还有另外一个地方就是 while(i <= 10).比如 while(i <= 10)写成while(i <= 10)和写成 while(i <= 100)就完全是两码事。所以这个地方叫判断部分,如图所示:

      然后对于这个循环来说,这个 i++也很重要,i 写成++,那这个时候每次+1,那循环10次。那如果这个地方写成 i+=2,这个地方次数就明显发生变化了,所以这个地方叫调整部分,如图所示:

      3个部分,初始化、判断和调整,3个部分任何一个部分发生变化,都会影响到循环,随着我们的代码写的越来越多,这3个部分会越来越分散,比如前面初始化又加了很多代码,判断里边又加了很多代码,这3个部分就离的越来越远,越来越远。

      而如果未来我们要改动我们的循环的时候,就会涉及到3个东西的一个改变,比如说我们的初始化变量从5开始,而一旦改,这3个部分离的比较远,这个时候就比较麻烦了,我得找到对应的部分才可以做,所以 while 循环从形式上讲,3个部分离的太远,就不太好

      而这个时候,出来一个 for 循环就解决了这个问题,for 循环把初始化、判断和调整3个部分集中在了一起

19.2 for 循环基本的书写形式

      for 循环的基本语法形式是这样的:for 后边跟一个圆括号,圆括号里边放的是表达式1分号,表达式2分号,表达式3。这三个表达式中,第一个表达式就是初始化;第二个表达式就是判断;第三个表达式就是调整。如图所示:

      如果我们现在,想用 for 循环来实现我们刚刚前面屏幕上打印的1-10,我们该如何去做呢?int i = 0,我们现在用 for 循环,for 循环中间有2个分号,3个部分

      第一个部分,我们要初始化,i 从多少开始呢?你既然要打印1-10,i 肯定从1开始,即 i = 1;第二个部分,i 判断的时候最大是10,所以我们写 i<= 10;第三个部分,也就是调整部分,i 每次是怎么变化的呢?i++就可以了

      下面一对大括号,这是 for 循环的循环体,里边进去之后就做一件事情,打印就可以了,如图所示:

      那这个代码,跟我们刚刚的这个循环是不是匹配的呢?i = 1就是我们的表达式1,就是我们的初始化部分,我让 i 从1开始;i <= 10这就是我们的判断部分,i++是我们的调整部分

      而且你会发现,我们把初始化、判断和调整三个部分放在了一起,这样从形式上讲,更优于 while 循环,这就是 for 循环的优势,所以使得我们在循环里边使用的时候,for 循环用的最多,次之是 while 循环,再次就是 do...while 循环。do...while 循环应用的是最少的。如图所示:

      for 循环的执行流程图,它的执行流程是首先不管三七二十一,上来执行表达式1,表达式1就是我们的初始化部分,初始化部分一执行之后,看我们的判断部分,判断部分如果为非0,就为真,我就进入循环,执行语句,语句执行完之后,再上来看表达式3调整,调整完了之后,再去判断,依此类推

      这个执行的过程中,你会发现这个第一步初始化部分是不是只被执行了一次,这就是 for 循环的特点,for 循环的特点是:初始化部分,只会被执行1次,不管循环多少次,我的初始化只有1次,如图所示:

19.3 for循环中的break和continue

      当然我们有细心也看到了:在这个循环执行的过程中,在循环语句里边,完全有可能出现 break 和 continue,那出现 break 和 continue 又是怎么执行的呢?我们继续往下学习

      我们还是按照这个代码来讲,如果 i 呢如果等于等于5,if(i == 5),那就 break,那这个代码的结果又是什么?根据我们对于 while 循环的了解,这个 break 的作用是跳出循环

      而现在如果我真的就跳出循环,等于5的时候终止,那5打印了么?没有。那这个代码的结果,应该还是我们曾经学过的1-4,这就是 for 循环里的 break,它也是用于终止整个循环,只要 break 执行了,循环就终止了,如图所示:

      那如果我们能够理解 break 的这种写法,那我们换成 continue 呢?现在的结果是什么?不会有死循环的可能性,为什么呢?continue 它是跳过本次循环 continue 后边的代码,它只是把 continue 后边的代码跳过去了

      也就是说,一旦跳过第71行代码之后,它紧接着上来要执行的是 i++,因为如果要执行了这个 printf("%d\n", i) 下来,就是执行 i++,所以当我们跳过去 continue 后边的代码的时候,它是不会把整个循环终止的

      而这一次循环 continue 后边的代码可能不执行了,上来还要执行 i++的,i++执行完之后 i 就变了,就变成6了,6就不会使得 continue 跳过了,所以6,7,8,9,10照样打印出来,如图所示:

      while 循环和 for 循环中 continue 的对比:while 循环里的 continue 和 for 循环里的 continue 是有所去别的,for 循环里的 continue 跳到调整部分进行 i++,而 while 循环里的 continue 完全有可能把调整部分跳过去,导致程序死循环

19.4 for语句的循环控制变量

for 循环的循环变量控制,我们有一些小小的建议:

19.4.1. 不可在 for 循环体内修改循环变量,防止 for 循环失去控制

      举个例子,i 是我们的循环变量,i 是1,i <=10,i++。调整是在圆括号内调整的,而如果有人在第84行代码写了个 i = 5,这个代码输出的结果,还是不是我们的1-10了?就不再是了,而且会导致这个代码死循环

      为什么这个代码死循环了呢?就是因为循环内部改变循环变量,本来循环变量是放在放在圆括号内去调整的,每次 i++一下,非要在第84行代码把循环变量改一下,所以代码就出问题了,如图所示:

      调整部分能不能不放在圆括号内,我把这个调整放在第84行代码行不行呢?也是可以的,如果你明确的知道,这个时候放在这可以,又不想在圆括号内部放,这是没问题的,如图所示:

      但是如果有一个人说,圆括号内好像漏东西了,i++再加上,这个时候我们会发现,在循环的调整部分调整了,而且在循环的里边 i++也把循环变量改了一次,那这个时候再看结果,结果就不再是我们想的那样1-10了,如图所示:

      因此,在循环体内,去改变循环变量,会让循环发生意想不到一些结果,所以尽量不要在 for 循环的循环体内修改修改循环变量,防止 for 失去控制。就是说,这个本来是这样的,后来发现跟我们现象的不一样,其实就是因为循环体内不小心把它改掉了

      有时候我们在 for 循环嵌套的时候,我们用个 j 变量来写,结果我们写着写着 for(j = 0; j <10; i++),这个时候的结果,可能也不会是我们想要的,比如我们打印一个东西 printf("hehe")

      我们这个代码是怎么执行的呢?i = 1的时候进来一次,打印1,打印完之后下面的循环就要走了,而这个循环走的过程中,我们每次判断的是 j < 10,j 肯定不小于10,因为这个过程我们没让 j 加加,而每次上来之后 i++,因为我们让 i++了,j 没有++,所以 j 永远都是小于10的

    所以这个代码我们会发现:这个循环内部,去改变循环变量,这种方式是不可取的,如图所示:

19.4.2. 建议 for 语句的循环控制变量的取值采用"前闭后开区间"写法

      就是说我们在写代码的时候,尤其是写这个 for 循环的时候,如果有机会的话,我们可以写前闭后开区间的写法

      举个例子,假设 int arr = {0},这是10个元素的一个数组,数组的下标是从0开始的,数组是通过下标来访问的,所以我就写 int i = 0,for(i = 0; i<10; i++),然后打印 arr[i],我们想通过下标 i 访问到这个数组的每个元素

      现在我在写这个循环变量的时候,左边 i 初始化的时候,从0开始的,i < 10最大是9,这叫开区间,i = 0叫闭区间,所以这叫左闭右开区间的写法,如图所示:

      有人就说我不这样写行不行?写成 i<= 9,这叫左右都是闭区间的写法,行不行呢?能不能达到效果呢?也是可以的,打印10个0这是妥妥的,如图所示:

      但是,不建议这样去写,我们建议左边闭区间,右边开区间的这种写法,这种写法更好一些,为什么更好呢,此时此刻,当我们这样去写的时候,我们会发现这个10好像具有某种意义,它循环10次,并不是说写成 <= 9就错了,而是说风格、写法、理解程度和可读性会更好一些。当然,这都是建议,不是绝对要这样写

19.5 for循环的变种

19.5.1 变种1

for 循环在写的时候,会有一些变种,举个例子,写个 for分号分号,然后打印 hehe,这好像在死循环的打印,为什么呢?因为关于这个 for 循环的初始化、判断和调整都可以省略,想省略哪一个,我们就省略哪一个,从语法上,都是支持的

      但是,判断部分的省略,判断部分恒为真,那这个代码最终死循环了,如图所示:

      初始化可以省略;判断也可以省略;调整也可以省略。或者三个同时都省略都行,但是一旦让判断部分省略,这个循环的判断部分就恒为真了,就可能会导致我们的死循环,所以我们要慎重省略,我们也不建议随便省略,为什么呢?当我们理解的不够透的时候,或者说我们把握不够足的时候,不要随便省略,因为随便省略会导致问题

      举个例子,假设 int i = 0,int j = 0,for(i = 0; i < 3; i++),for(j = 0; j < 3; j++),然后打印,结果会打印9个 hehe,如图所示:

      又有人好奇:前面的 i = 0,j 也等于0,不是赋值0了么?那第122行代码 i = 0不就多此一举么?第124行代码 j = 0不就多此一举么?我们把它去掉,去掉之后,我们再来看,这个时候我们代码打印3个 hehe

      为什么是3个 hehe 呢?这就是省略带来的原因,当 i = 0的时候,i < 3可以进来。进来之后,嵌套的 for 循环整体都要执行了,这个执行的过程中,j++ j 总会变成3,它不满足了,j 变成3的时候,已经打了3个 hehe 了,当我3个 hehe 打印完之后再上去回到第122行代码

      然后 i要加加一次,i++变成1,1 < 3进来,进来之后此时此刻的 j,没有被初始化成0了,j 还是我们上一次留的3,因为 j 在外边创建的,用完之后 j 已经变成3了,3没有改。没有改的时候 j < 3就进不去了,<3 进不去的时候,那里边的 for 循环就截止了

      截止的时候再上来,上来 i++变成2,2<3又进来了,你会发现这一次进来的时候,j 还是3,所以又没有打印,依此类推,当 i++变成3的时候,小于3就不满足条件了,它跳出去了,那整个就打印第一次 i = 0 的时候进来的3次 hehe,如图所示:

     而如果我们能在第124行代码加上一句话,叫 j = 0,每一次下来之后,j 不管变成多少,都先回归成0,这样的话就又能循环3次。我们省略给我们带来的一个不变,所以当我们还不会跑的时候,我们就慢慢地走,不要随便省略,这些省略给我们会带来很多的一些问题

19.5.2 变种2

      for 循环的循环变量控制,可能不是一个变量,int x = 0,int y = 0,我们这个循环是由2个循环变量控制的,xy同时控制,同时初始化。判断的时候 x < 2 && y < 5,++x,y++,当然这个前置后置都无所谓的

      这种循环也是支持的,就是说为了一个循环想要两个循环变量来控制的时候,也是可以的,如图所示:

19.6 for循环面试题

      请问循环要循环多少次,答案:循环0次!因为最开始 k 是0,i 是0,i 初始化成0,k 初始化成0,然后 k 被赋值成0, 这个地方是判断部分,判断部分把0赋给 k,这个表达式的结果就是0,0为假,循环一次都没进去(k = 0中是一个等号,它叫赋值,而不是判断)

      这个表达式的结果,它是为假的,为假就一次都不进去,所以这个循环循环了0次!如果写成 k == 0,最起码能够循环一次,如图所示:

      这个题不是在判断 k 是不是等于0,而是把0赋给 k,0为假,为假这个循环一次都不进去,所以这个循环0次

补充:

1. 为什么判断部分省略是恒为真?这个是规定,语法就是这么规定的

2. 如果 for 循环里边嵌套 for 循环,是两个 for 循环都跳过吗?不是,各自跳各自的,一个 break 只能跳出一层循环,只能跳出自己的循环。不可能跳出两层循环,那不就乱套了吗,那三层循环就跳出三层,四层循环就跳出四层,那怎么从第一层跳到第二层呢?我只跳出一层,那怎么做呢?是不是做不到了,所以它其实只能跳出一层,一个 for 循环只能跳出一层,如果多层嵌套,那我们要每一层都加上 break 才能跳出来

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值