第5章 循环结构程序设计 通常,许多问题的求解都包含一些重复执行的操作。例如,输入N 名学生的成绩、数 值计算中的方程迭代求根、集合中的数据遍历访问等。在程序设计中对于那些需要重复 执行的操作可以利用循环结构来进行处理。 循环结构是结构化程序设计的3种基本结构之一,其特点是在给定条件成立时,反复 执行某程序段,直到条件不成立时为止。给定的条件称为循环条件,反复执行的程序段称 为循环体。C语言提供了多种循环语句,常用的有while语句、do…while语句和for语 句。灵活、巧妙地掌握和使用这些语句可以实现各种不同的复杂程序功能。 本章将介绍3种循环语句的用法以及循环结构程序设计的基本方法,具体内容如下。 ● for循环。 ● while循环。 ● do…while循环。 ● break和continue语句。 5.1 for 循 环 for循环是最常用的循环结构,通常用于循环次数确定的情况,也可用于循环次数不 确定但给出循环结束条件的情况。 学一学 for循环的语法格式为 for(表达式1; 表达式2; 表达式3) { 循环体语句; } for循环的执行过程如下(流程图如图5-1所示)。 ① 计算表达式1。 84 C 语言程序设计 图5-1 for循环的流程图 ② 计算表达式2并判断其值;若其值为真,则转步骤③执 行循环体;若其值为假,则转步骤⑤结束循环。 ③ 执行循环体语句。 ④ 计算表达式3,转步骤②继续执行。 ⑤ 结束循环,执行for循环后的下一个语句。 说明 ①for语句的第一行被称为循环控制行,由3个表达式组 成。循环控制行最常见的形式为 for(初始表达式; 循环条件表达式; 循环变量表达式) 例如: for(i=0; i=0;i--) ④for(c=a' ';c<=z' ';c++) 例5-2 编写程序计算1+2+3+…+10,然后输出结果。 .................................... 解题思路.................................... 分析:本题是典型的累加求和问题,循环次数已知(10次),可以使用for循环进行实 第5 章 循环结构程序设计 85 现。具体步骤如下。 ① 变量定义:定义循环变量i和累加和变量s并初始化s=0。 ② 计算处理:利用for循环累加求和,先编写循环控制行for(i=1;i< =10; i++),再编写循环体s=s+i;。循环体只有一行,可以不用加大括号{}。 ③ 输出结果:输出s的值。 .................................... 程序代码.................................... #include "stdio.h" void main() { int i, s=0; for(i=1; i<=10; i++) s=s+i; printf("1+2+…+10=%d\n", s); } 程序运行结果如下。 1+2+…+10=55 程序注解 ① 若循环变量i在定义时已经初始化,则表达式1可省略,但分号不能省略,例如: int i=1, s=0; for(; i<=10; i++) 表达式3也可以省略,可以将表达式3(步骤④)提前合并到循环体(步骤③)中, 例如: for(i=1; i<=10;) s=s+i++; 若表达式1和表达式3同时省略,则等同于后面介绍的while循环。若三个表达式 同时省略,循环体将无限制地执行,形成无限循环(死循环)。 ② 表达式1可以是逗号表达式,可以将多个变量的初始化放在表达式1中,例如: int i, s; for(i=1, s=0; i<=10; i++) 表达式3也可以是逗号表达式,可以将简单循环体语句(步骤③)合并到表达式3(步 骤④)中,例如: int i, s; for(i=1, s=0; i<=10; s=s+i, i++) ③ 要理解循环变量与数据项之间的关系,本例中累加的数据项等于循环变量。若计 算2+4+…+20,循环变量从2变化到20,每次增加2,其他情况下不进行任何操作,对 86 C 语言程序设计 应程序可以编写如下。 for(i=2; i<=20; i=i+2) s=s+i; 也可这样思考:10项数据累加,循环变量从1到10,每次循环累加的数据项为当前 循环变量的2倍,对应程序可以编写如下。 for(i=1; i<=10; i++) s=s+i*2; 练一练 ① 编程实现输出5!。 ② 编程实现输出100以内所有是3的倍数或者含有3的正整数。 5.2 while 循 环 在for循环中,表达式1和表达式3均可省略,此时可以将表达式1放在for循环前 的变量初始化语句中,表达式3可以放在循环体语句中,例如: int i=1, s=0; for(; i<=10;) s=s+i++; 为了简化,将for循环的循环控制行修改为while(i<=10),这就是循环的另外一种 结构:while循环。 学一学 while循环是“当型”循环结构,其语法格式为 while(条件表达式) { 循环体语句; } 图5-2 while循环的流程图 while循环的执行过程如下(流程图如图5-2所示)。 ① 计算条件表达式的值,判断其值是否为真,若为真, 转步骤②执行,否则转步骤③执行。 ② 执行循环体语句。 ③ 结束循环,执行while循环后的下一个语句。 说明 ① 若循环体语句只有一条,大括号可以省略,否则必须 加上。 第5 章 循环结构程序设计 87 ② 条件表达式一般为关系表达式或逻辑表达式。 ③ 避免条件表达式始终成立,使程序进入“死循环”状态。 试一试 例5-3 计算s=1+2+3+…直到s 大于1000为止。 .................................... 解题思路.................................... 分析:本题也是典型的累加求和问题,不同于例5-2已知循环次数,题目给出了循环 终止的条件s>1000,相对应的循环条件表达式为s<=1000。具体解题步骤如下。 ① 变量定义:定义循环变量i和累加和变量s并初始化s=0。 ② 计算处理:利用while循环累加求和。 ③ 输出结果:输出s的值。 .................................... 程序代码.................................... #include "stdio.h" void main() { int i=0, s=0; while(s<=1000) { s=s+i; i++; } printf("s=%d\n", s); } 程序运行结果如下。 s=1035 程序注解 不同于for循环有初始化表达式进行循环变量的初始化,如果使用while循环,注意 在定义循环变量时要进行循环变量初始化(本例中的i=0),在循环体中不要忘记编写循 环变量变化表达式(本例中的i++),否则容易出错。 例5-4 计算1-1/2+1/3-1/4+1/5-…直到某项的绝对值小于等于10-6(该项不 累加)。 .................................... 解题思路.................................... 分析:本题也是累加求和问题,不同于例5-3,其累加项为实型数据且正负交替,在编 写程序时需要注意变量类型的定义、flag标记的设置以实现正负交替。具体步骤如下。 ① 变量定义:定义循环变量n和累加和变量s并初始化s=0,同时定义通项变量 item 以及标记变量flag。 ② 计算处理:利用while循环累加求和,当item的绝对值>1e-6时进行累加,然后改 88 C 语言程序设计 变flag标记,计算下一项的值并保存在item中,重复执行直至item的绝对值<=1e-6。 ③ 输出结果:输出s的值。 .................................... 程序代码.................................... #include "stdio.h" #include "math.h" void main() { int flag=1; double s=0, item=1, n=1; while(fabs(item)>1e-6) { s=s+item; flag=-flag; n=n+1; item=flag / n; } printf("s=%.6f\n", s); } 程序运行结果如下。 s=0.693148 程序注解 ① 本例中使用了C库函数中的求绝对值函数fabs,需要在本文件的开头加上文件包 含指令:#include"math.h"。 ② 当循环变量n定义为整型时,计算item 应避免使用两个整型变量直接相除,导致 结果为0,可使用item=flag*1.0/n;将参与计算数据转变为double类型进行计算。 练一练 用公式π 4≈1-13 +15 -17 +…求π的近似值,直到发现某一项的绝对值小于10-6 为止(该项不累加)。 5.3 do…while循环 学一学 除了for循环和while循环外,C语言还提供了do…while语句来实现循环结构。其 语法格式为 第5 章 循环结构程序设计 89 do { 循环体语句; } while(条件表达式); do…while循环的执行过程如下(流程图如图5-3所示)。 图5-3 do…while循环的流程图 ① 执行循环体语句。 ② 计算条件表达式的值,判断其值是否为真,若为 真,转步骤①执行,否则转步骤③执行。 ③ 结束循环,执行while循环后的下一个语句。 说明 ① do…while循环的特点是先无条件执行循环体, 然后判断循环条件表达式是否成立,因此循环体至少会 执行一次。 ② 若循环体语句只有一条,大括号可以省略,否则 必须加上。 ③ 条件表达式一般为关系表达式或逻辑表达式。 试一试 例5-5 使用do…while循环计算5!。 .................................... 解题思路.................................... 分析:本题是典型的连乘求积问题,注意在定义连乘积变量时初始化其值为1。具体 步骤如下。 ① 变量定义:定义循环变量i和连乘积变量s并初始化s=1。 ② 计算处理:利用do…while循环计算连乘积,先执行s=s*i,然后更改循环变量, 判断循环条件i<=5是否成立,条件成立时继续执行循环体,直至i>5结束循环。 ③ 输出结果:输出s的值。 .................................... 程序代码.................................... #include "stdio.h" void main() { int i=1, s=1; do { s=s*i; i++; } while(i<=5); printf("s=%d\n", s); } 程序运行结果如下。 s=120 90 C 语言程序设计 程序注解 当while后面的表达式一开始就为假时,while和do…while两种循环的结果是不 同的。 练一练 求出100~999的所有水仙花数。水仙花数是指一个三位数其各位数字的立方和等 于该数本身(例如13+53+33=153)。 5.4 循环的嵌套 学一学 一个循环体内又包括另一个完整的循环结构,称为循环的嵌套。内嵌的循环中还可 以嵌套循环,这就是多层循环。前面介绍的3种循环之间可以互相嵌套。 嵌套循环有很多应用场景,图形输出是嵌套循环的典型应用之一,下面通过例题讲解 如何利用两层循环进行图形的输出。 试一试 例5-6 编写程序,输出图5-4中的九九乘法表。 图5-4 九九乘法表 .................................... 解题思路.................................... 分析:图形问题一般有行有列,本题中的九九乘法表共有9行,设计一个循环(一般 称为外循环),控制循环打印9行。针对第i 行共有i 列,再设计一个循环(一般称为内循 环),控制循环打印每行的i 列数据。每行结束后需要换行,列与列之间可以填充一个空 格。具体步骤如下。 ① 变量定义:定义两个循环变量i和j,分别用来控制打印行和打印列。 ② 外循环:先设计一个外循环,i从1变化到9,循环体负责打印第i行数据。 ③ 内循环:在外循环的循环体内再设计一个内循环打印第i行数据,j从1变化到i, 在内循环的循环体内打印第i行第j列数据i*j。 .................................... 程序代码.................................... #include "stdio.h" 第5 章 循环结构程序设计 91 void main() { int i=1, j=1; for(i=1; i<=9; i++) { for(j=1; j<=i; j++) { printf("%d*%d=%-2d ", i, j, i*j); } printf("\n"); } } 程序注解 ① 外循环的循环体包括一个内循环和一个换行语句,因此外循环的循环体需要加上 大括号,将两者作为一个整体。 ② %-2d用于限制打印的数据占两个字符宽度并左对齐。 练一练 编写程序,打印输出1~5的数字金字塔,如图5-5所示。 图5-5 数字金字塔 “百钱买百鸡”类问题是嵌套循环的另一典型应用,下面通过例题讲解如何利用两层 循环解决此类问题。 试一试 例5-7 已知公鸡每只5元,母鸡每只3元,小鸡1元3只。要求用100元钱正好买 100只鸡,问公鸡、母鸡、小鸡各多少只? .................................... 解题思路.................................... 分析:公鸡可能取值0~20,母鸡可能取值0~33,对所有可能的公鸡取值、母鸡取值 进行穷举。先设计一个循环对公鸡可能取值x 进行穷举。当公鸡取值x 固定时,再设计 一个循环对母鸡可能取值y 进行穷举。当5*x+3*y+(100-x-y)/3==100时,满 足题目要求,输出对应结果,然后继续对下一组可能取值进行判断。具体步骤如下。 ① 变量定义:定义两个循环变量x和y,分别用来控制公鸡可能取值和母鸡可能 取值。② 外循环:先设计一个外循环对公鸡可能取值进行循环,x从0变化到20。 ③ 内循环:在外循环的循环体内再设计一个内循环对母鸡可能取值进行循环,y从 0变化到33,在内循环的循环体内负责对x、y、100-x-y这样一组数据进行判断,满足要 92 C 语言程序设计 求则输出,否则更改循环变量,继续进行下一组数据的判断。 .................................... 程序代码.................................... #include "stdio.h" void main() { int x=0, y=0, c=1; for(x=0; x<=20; x++) { for(y=0; y<=33; y++) { if(5*x+3*y+(100-x-y)/3==100 && (100-x-y)%3==0) { printf("%d: 公鸡%d 只,母鸡%d 只,小鸡%d 只\n", c++, x, y, 100-x-y); } } } } 程序运行结果如下。 1: 公鸡0 只,母鸡25 只,小鸡75 只 2: 公鸡4 只,母鸡18 只,小鸡78 只 3: 公鸡8 只,母鸡11 只,小鸡81 只 4: 公鸡12 只,母鸡4 只,小鸡84 只 程序注解 小鸡取值需要被3整除,因此在对每组数据判断时增加了(100-x-y)%3==0。 练一练 某工地需要搬运砖块,已知男人一人搬3块,女人一人搬2块,小孩两人搬1块。问 45人正好搬45块砖有多少种搬法? 5.5 break语句和continue语句 以上介绍的循环都是根据事先指定的循环条件正常终止的,但有时在某种情况下需 要提前终止正在执行的循环,这时可以用break语句和continue语句实现。 5.5.1 用break语句提前终止循环 学一学 break语句只能用在switch语句和循环语句(for、while、do…while循环)中。当