循环结构中,程序会重复地执行同一段代码,直到条件不再满足,或者遇到强行跳出语句。循环结构主要包括while循环、do…while循环和for循环,这3种循环语句可以相互转换。所谓循环控制,就是通过循环控制变量和条件表达式,以及break语句、continue语句和goto语句,控制程序的重复执行过程,当不符合循环条件时停止循环。循环结构可以使程序代码更加简洁,减少冗余,是程序设计人员必须掌握的。
本章知识架构及重难点如下:
while循环语句的一般形式如下:
while(表达式) 语句块;
其中,“表达式”一般是关系表达式或逻辑表达式,表示循环条件,值是一个逻辑真值或假值。
while循环的执行过程为:先计算“表达式”的值,当值为真(非0)时,执行“语句块”;执行完“语句块”,再次计算“表达式”的值,如果为真,继续执行“语句块”……这个过程会一直重复,直到“表达式”的值为假(0),就退出循环,执行while循环后面的代码。流程图如图5.1所示。
循环语句块通常是用大括号括起来的多条简单语句,又称为循环体。循环语句反复执行的就是循环体中的内容。
【实例5.1】 计算1~10的累加和(while版)。 (实例位置:资源包\TM\sl\5\1)
图5.1 while循环流程图
计算1~10的累加和就是计算1+2+…+10。使用while循环求解时,需要有一个变量从1变化到10,将该变量命名为i。i既作为整个循环的控制变量(循环条件为i<=10),又作为依次累加的数。还需要一个变量sum,不断和i进行加法运算,并记录运算结果。变量i每增加1时,就和变量sum进行一次加法运算,因此变量sum记录的就是累加和。本例程序的流程图如图5.2所示。
具体代码如下:
程序先对变量sum和i进行初始化,然后执行while循环。循环条件是i<=10,要执行的循环体是一个复合语句,语句“sum=sum+i;”完成累加功能,语句“i++;”完成由1到10的递增变化。当i<=10时,反复执行循环体,一共要执行10次。程序运行结果如图5.3所示。
图5.2 实例5.1流程图
图5.3 while版计算1~10累加和
初学循环语句时,读者经常会因为错写条件表达式,使循环多执行一次或少执行一次,这类错误称为“差一错误”。例如,把number <= 20写作number < 20,就会少执行一次循环。
使用while循环的注意事项如下:
(1)“表达式”不能为空,如果为空则不合法。
(2)“表达式”中,可以用非0代表逻辑真值(true),用0代表逻辑假值(false)。
例如,下述语句是一个无限循环语句。此时循环体中必须有结束循环的条件,否则系统将陷入死循环。
while(1) { ... }
下述语句是一个不会进行循环的语句。
while(0) { ... }
(3)循环体中必须有改变“表达式”值的语句,否则将成为死循环。
(4)“while(条件表达式)”后面不能添加英文分号(;)。
编程训练(答案位置:资源包\TM\sl\5\编程训练\)
【训练1】打印100次名字 利用while循环,输出100个自己的名字。
【训练2】单细胞细菌繁殖实验 生物实验室做单细胞细菌繁殖实验,每一代细菌数量都会成倍数增长。一代菌落中只有1个细菌,二代菌落中分裂成2个细菌,三代菌落中分裂成4个细菌,以此类推,请问第十二代菌落中的细菌数量。
do...while循环语句的一般形式如下:
do 语句块 while(表达式);
其中,do为关键字,必须与while配对使用;do与while之间的语句为循环体,同样用大括号括起来;“表达式”同样是关系表达式或逻辑表达式,表示循环条件,值是一个逻辑真值或假值。
do…while循环与while循环的不同之处在于:它会先执行语句块,再判断表达式是否为真。如果为真,则继续循环;如果为假,则终止循环。因此,do…while循环至少要执行一次语句块。
do...while循环语句的流程图如图5.4所示。值得注意的是,do...while循环后要有分号“;”。
【实例5.2】 计算1~10的累加和(do…while版)。 (实例位置:资源包\TM\sl\5\2)
图5.4 do...while循环流程图
图5.5 实例5.2流程图
本实例中,将使用do…while循环语句求解1~10的累加和。do...while循环和while循环实现累加的循环体语句相同,只是执行循环体的先后顺序不同。本例程序的流程图如图5.5所示,具体代码如下:
程序运行结果如图5.6所示。
图5.6 do...while版计算1~10累加和
程序中先将变量sum和i初始化,然后执行循环体,进行累加赋值运算和变量i自增运算,接着判断循环条件,看变量i的值是否已经大于10,如果大于则跳出循环,否则就继续执行循环体。
使用do…while循环的注意事项如下。
(1)即使循环条件不成立,循环体也会执行一次。使用时要注意各变量的变化。
(2)表达式不能为空,如果为空则不合法。
(3)表达式可以用非0代表逻辑真值(true),用0代表逻辑假值(false)。
(4)循环体中必须有改变条件表达式值的语句,否则将成为死循环。
(5)“while(条件表达式)”后面要添加英文分号“;”。
while循环是“先判断,后执行”,do…while循环是“先执行,后判断”。也就是说,当初始条件不成立时,while循环一次也不会执行,而do…while循环会执行一次。
编程训练(答案位置:资源包\TM\sl\5\编程训练\)
【训练3】模拟用户登录 模拟用户登录,如果用户输入密码错误,要求用户再次输入,直到输入正确密码。
【训练4】猴子摘桃 猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个。第二天早上又将第一天剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃前一天剩下的一半零一个。到第10天早上想再吃时,发现只剩下一个桃子了。编写程序,求猴子第一天共摘了多少个桃子,利用do…while循环计算。
for循环语句的一般格式如下:
for(表达式1;表达式2;表达式3) 语句块
其中,“表达式1”仅在第一次循环时执行,通常是一个赋值表达式,用来对循环变量进行初始化赋值;“表达式2”是一个关系表达式,又称为循环条件,决定了是否还要继续下次循环;“表达式3”通常是一个带有自增或自减操作的表达式,用于使循环条件逐渐变得“不成立”。
for循环的执行过程如下,其流程图如图5.7所示。
(1)先执行“表达式1”。
(2)再执行“表达式2”,如果其值为真(非0),则执行循环体,否则结束循环。
(3)执行完循环体后,再执行“表达式3”。
(4)重复执行步骤(2)和(3),直到“表达式2”的值为假,就结束循环。
【实例5.3】 计算1~10的累加和(for版)。 (实例位置:资源包\TM\sl\5\3)
计算1~10累加和需要有一个循环控制变量i和一个记录累加和的变量sum。for循环的3个表达式中,“表达式1”对循环控制变量i赋初值,“表达式2”给出循环条件i<=10,“表达式3”实现循环控制变量i由1到10的递增变化。具体代码如下:
实例5.3的流程图如图5.8所示,程序运行结果如图5.9所示。
图5.7 for循环执行过程
图5.8 for循环计算1~10的累加和
图5.9 程序运行结果
对比实例5.1和实例5.3,可以清晰地发现,for循环之所以有3个表达式,其实就是将while或do…while循环中有关循环控制变量赋初值(i=1;)、循环控制变量自增变化(i++;)的两处代码也都合并到了for后的括号中。因此,整体代码看起来更加紧凑、灵活。
初学for语句时,读者很容易误用逗号去分隔3个表达式。例如:
for(i=1,i<100,i++)
注意,这里代表的是3个语句,因此要用分号进行分隔。
使用for循环的注意事项如下。
(1)变量一般声明在for循环语句外,也可以直接在表达式1中声明变量。例如:
(2)for循环中的表达式1、表达式2、表达式3都可以省略,但分号必须保留。
省略表达式1时,需要在for循环外声明循环控制变量i并赋初值。例如:
如果在循环外声明了变量i却忘记赋初值,程序能通过编译,但运行结果通常是错误的。因为编译器会为变量赋一个默认初值(一般为一个比较大的负数),从而导致程序运行结果不正确。
省略表达式2,也就是省略了循环终止条件,如果不做其他处理,程序将陷入死循环。死循环对程序的危害很大,一定要避免。
省略表达式3时,需要在for循环体中加入修改变量的语句。
省略表达式1和表达式3后,就和while循环一样了。例如:
编程训练(答案位置:资源包\TM\sl\5\编程训练\)
【训练5】判断是否为素数 使用for循环,判数某个输入的数是否是素数(即质数)。
【训练6】计算小球第6次反弹的高度 一个球从80m高度自由落下,每次落地后反弹的高度为原高度的一半,第6次落地时共经过多少米?第6次反弹多高?
循环控制包含两方面的内容,一是循环控制变量的变化方式,二是循环控制的跳转。循环控制的跳转需要用到break和continue关键字,这两条跳转语句的跳转效果不同,break是中断整个循环体,continue是跳出该循环体的本次执行。除此以外,goto语句也可以用来跳出循环。
无论是for循环,还是while、do...while循环,都需要有一个循环控制变量。
循环控制变量,就是循环过程中用来控制循环次数和循环条件的变量。它通常作为循环的计数器,用于追踪循环的进度和控制循环的终止条件。在for循环中,循环控制变量在循环的起始时进行初始化,并在每次循环迭代中更新其值。
循环控制变量的变化方式有两种:一是递增,二是递减。使用递增方式还是递减方式,与循环条件以及变量的初值和限定范围值有关。如果初始值大于限定范围值,使用递减方式;如果初值小于限定范围值,使用递增方式。
【实例5.4】 计算1~10的累加和(递减版)。 (实例位置:资源包\TM\sl\5\4)
使用循环变量的递减方式计算1~10累加和。程序代码如下:
程序中,在for循环的“表达式1”中声明变量i并赋初值10;“表达式2”中限定循环控制变量i是否大于等于1,如果小于1,就停止循环;“表达式3”使循环控制变量由10~1递减变化,程序输出结果仍是“the result :55”。
4.5节中介绍了break语句可以跳出switch结构。在循环结构中,同样可用break语句跳出当前循环体,从而中断当前循环。
在3种循环语句中使用break语句的形式如图5.10所示。
【实例5.5】 遇到负数就退出。 (实例位置:资源包\TM\sl\5\5)
本实例中,使用for循环输入10个数,将这10个数进行累加,但是当输入负数时,立即停止累加,直接输出之前数据的累加结果。具体代码如下:
程序中需要用户输入10个数,然后计算10个数的和,但当输入的数为负数时,就退出整个for循环,停止累加,并输出前面累加的结果。例如,依次输入4个正数,当第5个输入数为-1时,退出循环,输出前4个正数的累加结果。程序运行效果如图5.11所示。
图5.10 break语句的使用形式
图5.11 程序运行结果
当存在多层循环嵌套时,break语句只会使程序流程跳出包含它的内层循环结构,即只能跳出一层循环。
continue语句是对break语句的补充。continue不是立即跳出循环体,而是跳过本次循环结束前的语句,回到循环的条件测试部分,重新开始执行循环。在for循环语句中遇到continue后,首先执行循环的增量部分,然后进行条件测试。在while和do…while循环中,continue语句使控制直接回到条件测试部分。
在3种循环语句中使用continue语句的形式如图5.12所示。
图5.12 continue语句的使用形式
【实例5.6】 跳过负数继续累加。 (实例位置:资源包\TM\sl\5\6)
本实例要求,遇到负数就跳过,继续累加下面的数据,最后输出累加结果。具体代码如下:
程序中需要用户输入10个数,然后计算10个数的和。当输入的数为负数时,退出本轮循环(即本轮不再执行“sum+=n;”语句,也就是不对负数进行累加),直接进行下一轮循环。例如,输入9个数全为1,还有一个数为-1,最终输出结果为9。
goto语句又称为无条件跳转语句,用于改变语句的执行顺序。goto语句的一般格式如下:
goto 标签;
其中,标签是用户自定义的一个标识符。goto语句可将程序跳转到由“label:”代码定义的标签处继续执行。
【实例5.7】 计算1~10的累加和(goto版)。 (实例位置:资源包\TM\sl\5\7)
本实例中,使用if语句判断变量是否小于10,如果小于就用goto语句跳转到标签label处,使变量进行累加并自增。具体代码如下:
本例程序中,通过goto语句和标签实现了一定的循环功能。当语句执行到“if (i<10)”时,如果条件成立,就跳转到标签“label:”处,再一次执行循环变量i的自增运算和累加求和运算。当i自增至10时,计算完累加和,发现“if (i<10)”条件不满足,不再跳转,而是输出累加和计算结果。
使用goto语句时的注意事项如下。
(1)定义标签时,其后不能紧跟“}”。例如,下面的程序代码是非法的。
上述代码中,标签后没有执行代码,因此会出现编译错误。解放方法为:补充对应的执行代码。
(2)goto语句不能跳过除复合语句外的其他变量定义语句。例如,下面代码中goto语句试图跳过变量i的定义语句,导致编译错误。
解决方法为:将变量定义放在复合语句中。
goto语句是一种古老的跳转语句,会使程序的执行顺序变得混乱,CPU执行效率也较低。因此,实际开发中要慎用goto语句。
编程训练(答案位置:资源包\TM\sl\5\编程训练\)
【训练7】蜗牛多久能爬到井口 有一口井深10m,一只蜗牛从井底向井口爬,白天向上爬2 m,晚上向下滑1 m,问多少天可以爬到井口。
【训练8】输出可以使用的座位号 某剧院发售演出门票,演播厅观众席有4排,每排有10个座位。为了不影响观众视角,在发售门票时,屏蔽掉最左一列和最右一列的座位。编写程序,输出可以使用的座位号。
循环有for、while、do...while 3种方式,这3种方式可以相互嵌套。例如,在for循环中嵌套for循环:
在while循环中嵌套for循环:
【实例5.8】 打印金字塔形状。 (实例位置:资源包\TM\sl\5\8)
使用嵌套的for循环输出由字符“*”组成的5层金字塔形状。第1层有一个“*”,第2层有两个“*”……第5层有5个“*”。具体代码如下:
程序中,最外层的for循环控制输出的行数,内层的第一个for循环控制字符“*”前的空格数,第二个for循环控制输出字符“*”的个数。内层第一个循环中,随着行数的增加,字符“*”前的空格数越来越少。内层第二个for循环中,输出和行号有关的奇数个字符“*”。程序运行结果如图5.13所示。
图5.13 打印金字塔形状
【实例5.9】 输出乘法口诀表。 (实例位置:资源包\TM\sl\5\9)
使用嵌套的for循环输出乘法口诀表。具体代码如下:
程序使用了两层for循环,外层for循环控制行数,使其由1到9变化,内层for循环控制列数,保证随着行数的增加,列数也在增加,最后形成的第9行有9列。同时,i和j还要作为乘法口诀表中的被乘数和乘数。程序运行结果如图5.14所示。
图5.14 输出乘法口诀表
随着学习的深入,读者应逐渐意识到“编程思维”在实际开发中的重要性。
编程思维的核心,不是选择哪种开发语言,也不是具体的语法规范,甚至不是算法或数据结构本身,而是如何分解问题,从中发现规律,建立解决问题的模型,并映射到合适的数据结构和算法上,然后才能根据算法编写程序进行实现。
编程思维反映出两种核心能力,一是算法设计能力,二是代码实现能力。要想形成自己的编程思维,就需要多思考,多琢磨,多读优秀的源代码,同时进行大量的练习,使自己逐渐能站在计算机的角度去思考问题。
编程训练(答案位置:资源包\TM\sl\5\编程训练\)
【训练9】打印菱形 用嵌套for循环语句编写程序,打印如下所示的菱形。
* *** ***** ******* ***** *** *
【训练10】打印杨辉三角 用嵌套for循环语句编写程序,打印如下所示的杨辉三角(输出前5行)。
1 1 1 1 2 1 1 3 3 1 1 4 6 4 1
答案位置:(资源包\TM\sl\5\实践与练习\)
综合练习1:分期付款 用户输入想买的手机价格,减掉首付300元,剩下的钱分6个月分期付款。已知每个月的利息是0.6%,使用for循环计算每个月需要还多少钱。运行结果如下:
请输入想买的手机价格:2699 手机的总价格是:2699.0元 首付300元后还剩2399.0元 将所剩2399.0元分6期付款: 从买手机开始,接下来的6个月每月需要还414.4元
综合练习2:农夫卖瓜 农夫有1020个西瓜,第一天卖掉一半多2个,第二天卖掉剩下的一半多2个,如此循环下去,需要卖几天才能卖完。使用while循环进行结算,运行结果如下:
这些西瓜,一共卖8天
综合练习3:模拟自动售货机 某自动售货机有3种饮料,价格分别为3元、5元、7元。假设该售货机仅支持1元硬币支付,编写程序,使用do…while循环和else if语句模拟其收费系统。运行结果如下:
请设入1元硬币: 1 请设入1元硬币: 1 请设入1元硬币: 1 可买3元饮料 请设入1元硬币: 5 您投入的不是1元硬币,不符合要求!
综合练习4:猜数字游戏 编写一个猜数字的小游戏,随机生成一个1~10(包括1和10)的数字作为基准数,玩家每次通过键盘输入一个数字,如果输入的数字和基准数相同,则成功过关,否则重新输入。运行结果如下:
请输入一个数字: 200 你猜大了,请重新输入: 150 你猜大了,请重新输入: 140 你猜小了,请重新输入: 145 你猜小了,请重新输入: 147 恭喜你,猜对了!!
综合练习5:百钱买百鸡 5文钱可以买一只公鸡,3文钱可以买一只母鸡,1文钱可以买3只雏鸡。现在用100文钱恰好可买100只鸡,问公鸡、母鸡和雏鸡各有多少只。使用嵌套循环进行计算,运行结果如下:
公鸡0,母鸡25,雏鸡75 公鸡4,母鸡18,雏鸡78 公鸡8,母鸡11,雏鸡81 公鸡12,母鸡4,雏鸡84
综合练习6:倒序输出九九乘法表 请用程序输出倒序的乘法口诀表。使用嵌套循环进行输出,运行结果如下:
9* 9 = 81 9* 8 = 72 9* 7 = 63 9* 6 = 54 9* 5 = 45 9* 4 = 36 9* 3 = 27 9* 2 = 18 9* 1 = 9 8* 8 = 64 8* 7 = 56 8* 6 = 48 8* 5 = 40 8* 4 = 32 8* 3 = 24 8* 2 = 16 8* 1 = 8 7* 7 = 49 7* 6 = 42 7* 5 = 35 7* 4 = 28 7* 3 = 21 7* 2 = 14 7* 1 = 7 6* 6 = 36 6* 5 = 30 6* 4 = 24 6* 3 = 18 6* 2 = 12 6* 1 = 6 5* 5 = 25 5* 4 = 20 5* 3 = 15 5* 2 = 10 5* 1 = 5 4* 4 = 16 4* 3 = 12 4* 2 = 8 4* 1 = 4 3* 3 = 9 3* 2 = 6 3* 1 = 3 2* 2 = 4 2* 1 = 2 1* 1 = 1