第5 章循环结构程序设计 案例导入———计算30名学生“C语言程序设计”课程的平均成绩 【问题描述】 从键盘输入30名学生“C语言程序设计”课程的成绩,计算该课程的平 均成绩。 【解题分析】 要处理该问题,首先要了解题目的含义和要求,该题目只需要输入30 名学生的成绩,并不需要保存这些成绩,因此只需要输入一个成绩做一次累加,此操作要 处理30次,之后用成绩的累加值除以30就可以得到平均成绩。使用之前学过的顺序结 构可以处理该问题: 首先定义3个变量分别存储学生成绩score、成绩的和total和平均成绩average,根 据目前学校的常规约定,学生成绩score可以定义为整型,成绩的和total定义为整型,平 均成绩average定义为单精度浮点型。学生成绩通过键盘输入,不需要给出初值;成绩的 和total需要做累加,应该给出初值0;平均成绩average直接被赋值,也不需要给出初值。 int score,total=0; float average; 然后输入一个学生的“C 语言程序设计”课程的成绩score,并累加到成绩的和 total中。 scanf("%d",&score); total+=score; 以上两条语句需要再重复29次,才能完成30名学生“C语言程序设计”课程的成绩 的输入和累加。 最后利用total除以30得到平均值,并保留两位小数输出。 average=total/30.0; /*total 是整型变量、30 是整型常量,想得到实型结果则需 要将其中一个转化为实型数据*/ printf("average=%.2f\n",average); 利用以上方式确实能够完成题目要求,但显然不可取。此题目要求得到30名学生的 平均成绩,重复书写30次相同的代码还可以忍受,但如果要求得到3000、30000名学生 C 语言程序设计(第3 版·微课版) 的平均成绩,输入和累加的代码段就需要重复书写3000、30000次,那是难以想象的。工作 量太大,也导致程序冗长、可读性差。另外,如果学生人数不确定,只是要求计算一批学生的 “C语言程序设计”课程的平均成绩,使用之前的顺序结构和选择结构根本没办法完成。 实际上,每种计算机的高级语言都提供了循环控制结构,用来处理需要重复操作的运算。 在C语言中,可以使用循环语句完成该题目: #include <stdio.h> int main() { int score,i,total=0; float average; i=0; //变量i 初值设置为0 while(i<30) //当i 的值小于30 时执行花括号内的语句 { scanf("%d",&score); //输入一名学生的成绩 total+=score; //将该学生的成绩累加到total 中 i++; //每执行一次循环i 的值加1 } average=total/30.0; //循环结束后计算平均值赋给变量average printf("average=%.2f\n",average); //输出30 名学生的平均成绩 return 0; } 可以看出,用一个循环语句(while语句)就可以解决代码段重复书写30次的问题。 导学与自测 扫二维码观看本章的预习视频———循环结构的理解,并完成以下课前自测题目。 【自测题1】 下面程序的输出结果是( )。 #include <stdio.h> int main() { int i,sum=0; i=1; while(i<11) { sum+=i; i++; } printf("sum=%d\n",sum); return 0; } A.55 B.sum=55 C.sum=66 D.sum=65 【自测题2】 下面程序的输出结果是( )。 #include <stdio.h> int main() { int i,sum=0; 92 循环结构 的理解 第5 章 循环结构程序设计 i=1; while(i<11) { i++; sum+=i; } printf("sum=%d\n",sum); return 0; } A.55 B.sum=55 C.sum=65 D.sum=66 【自测题3】 下面程序段中while循环的执行次数是( )。 int t=10; while(t=1) { t++; } A.一次也不执行 B.执行10次 C.无限次 D.语法错误 我们在处理实际问题时,有些问题的处理过程是采用重复的动作来完成的。例如,要 统计某班学生某一学期某门课程的平均成绩,就需要对每名学生的成绩进行输入和累加, 这个输入和累加的过程是需要不断重复进行的。这种重复执行的过程在计算机的程序设 计中称为循环。 循环结构是结构化程序设计的3种基本结构之一,也是程序流程控制中一种很重要 的结构,几乎在所有的解决实际问题的应用程序中都要用到循环控制结构。它与顺序结 构、选择结构一起实现复杂结构的程序设计。 现实生活中所遇到的循环形式根据实际问题的不同,其表现形式也不同,有的是已知重 复(循环)次数,如上面提到的统计某班学生某一学期某门课程的平均成绩,学生人数定了, 重复计算(循环)的次数也就确定了;有的则不能预知重复(循环)次数,如从1开始,多少个 自然数的和刚好能超过10000。为解决上述两类循环问题,C语言提供了3种实现循环结 构的语句,分别是while语句(当型循环)、do…while语句(直到型循环)和for语句。 本章首先介绍C语言实现循环结构的这3种循环语句的语法及使用方法,然后对能 够改变循环体中语句执行顺序的continue语句和break语句做简单介绍,最后介绍使用 循环结构解决的一些实际问题。 5.1 while语句 while语句的一般格式为 while(循环条件表达式) {循环体语句} 93 语句的执行过程:在执行while语句时,先对循环条件表达式进行计算,若其值为真 (非0), 则执行循环体语句,然后重复上述过程,直到循 环条件表达式的值为假(0)时,循环结束,程序控制转 至while语句的下一个语句。这种先判断循环条件的 循环称为当型循环。语句的执行过程如图5. 使用while语句时,应注意以下4个问题 1 。 所示。 (1)while语句的特点是“先判断,后执行”,如果循 环条件表达式的值一开始就是0,则循环体一次也不执 行,但循环条件表达式是要执行的。 图5.wie语句流程图(2)while语句中的循环条件表达式一般是关系表 1 hl 达式或逻辑表达式,但也可以是数值表达式或字符表达式,只要能判断真假即可。 (3)循环体如果是一条语句,则花括号可以省略。 (4)在循环体中,必须有使循环条件趋向于不成立(假)的语句。如果没有使循环条 件趋向于不成立(假)的语句,则循环永远不能结束,称为死循环。 100 例5.计算Σ。即计算1+2+3+…+100,也就是求自然数1100 之累加和。 1 n ~ n= 问题分析:这是一(1) 个累加(求和)问题,其计算过程如下。第一次计算0+1;第二次用 第一次的求和结果加上2,实际计算的是前两项的和;以此类推,第 n 次用第n-1次的求 和结果加上n,即为自然数1~ n 之和,当 n 的取值为100 时,即得到自然数1~100 之和。 按照这一思路,可以构建如下算法。 (1)声明一个变量(sum)存放加法的和,并设置初值为0。 (2)将1加入sum 。 (3)将2加入sum 。 (4)将3加入sum 。 … (101)将100 加入sum 。 (102)输出sum 的值。 101) 可以看出,步骤(2)~(描述的是相同的动作,因此,完成这种重复的操作可以 利 用C语言提供的循环结构来实现。 因此,程序可如下设计。 (1)声明一个变量sum,初值为0。 (2)设置变量n,初值为l。 (3)将n加入sum 。 (4)让n的值加1。 (5)当n<=100 成立时,重复执行步骤(3)和(4); 当n>100 时,执行步骤(6)。 (6)输出sum 的值 。 从上面的描述可以看出,步骤(3)和(4)要重复执行100 次 。 C 语言程序设计(第 3 版·微课版) 第5 章 循环结构程序设计 程序如下: #include <stdio.h> int main( ) { int n,sum=0; n=1; while(n<=100) { sum=sum+n; //求和 n++; } printf("sum=%d\n",sum); return 0; } 程序运行结果: 从例5.1中可以看出,当给定条件成立时,反复执行某几个步骤(程序段),直到条件 不成立为止。给定的条件称为循环条件,反复执行的程序段称为循环体。其中,变量n称 为循环控制变量,在循环体外的赋值n=1中的1称为循环控制变量的初值,在while(n<= 100)中的100称为循环控制变量的终值,在循环体内的n++称为循环控制变量的增量。 为了保证循环能正常退出,循环体内的循环控制变量的增量一定是使循环控制变量的值 从初值慢慢接近终值,直到循环条件为假。 例5.2 现有某班若干学生的C语言成绩,求该班学生的C语言的平均成绩。 问题分析:本例仍然是一个累加(求和)问题。但本题没有确定学生人数,不知道应 该从键盘输入多少名学生的C语言成绩,即不知道循环多少次。这种类型的题目的解决 办法可以采用以下两种方式。第一种方式是定义一个整型变量count,用来存储学生人 数,即循环次数,并从键盘输入;之后利用循环每输入一个成绩score就进行一次累加,当 所有count名学生的成绩输入完成后,此时total的值即为count名学生的C语言成绩的 累加和,用成绩的累加和除以count即得到该门课程的平均成绩。 因此,程序可如下设计(学生成绩为实型数据)。 (1)声明整型变量count,存放学生人数;声明实型变量total,初值为0,存放成绩的 累加和;声明实型变量score,存放每名学生的成绩;声明实型变量average,存放平均 成绩。 (2)声明一个整型变量i作为循环控制变量,初值为0。 (3)输入学生人数,即为变量count赋值。 (4)当i<count成立时,重复执行步骤(5)~(7);当i>=count时,执行步骤(8)。 (5)输入每名学生的成绩,即为变量score赋值。 (6)将score加入total中。 (7)循环控制变量i加1。 (8)计算average=total/count,输出average的值(平均值保留1位小数)。 95 计算平均值 C 语言程序设计(第3 版·微课版) 程序如下: #include <stdio.h> int main( ) { int count; float total=0,score,average; int i=0; printf("请输入学生人数:"); scanf("%d",&count); printf("请输入学生成绩:"); while(i<count) { scanf("%f",&score); total=total+score; i++; } average=total/count; printf("%d 名学生的C 语言平均成绩:% .1f\n",count,average); return 0; } 程序运行结果1: 程序运行结果2: 第二种方式是根据题目的描述找出处理问题的方法,本例处理的是一门课程的学生 成绩,而学生成绩的取值范围是大于或等于0并且小于或等于100的。可以利用这个条 件设置循环,即当输入的数据满足条件时进行累加;否则退出循环,并计算平均成绩。 因此,程序可如下设计(学生成绩为实型数据)。 (1)声明整型变量count,初值为0,用来统计学生人数;声明实型变量total,初值为 0,存放成绩的累加和;声明实型变量score,存放学生的成绩;声明实型变量average,存放 平均成绩。 (2)输入第一名学生的C语言成绩,即为变量score赋值。 (3)当score满足大于或等于0并且小于或等于100时,重复执行步骤(4)~(6);当 score小于0或者大于100时,执行步骤(7)。 (4)将score加入total中。 (5)统计学生人数的变量count加1。 (6)输入下一名学生的成绩,即为变量score赋值。 (7)计算average=total/count,输出average的值(平均值保留1位小数)。 程序如下: #include <stdio.h> 96 第5 章 循环结构程序设计 int main( ) { int count=0; float total=0,score,average; printf("请输入学生成绩:"); scanf("%f",&score); while(score>=0 && score<=100) { total=total+score; count++; printf("请输入学生成绩:"); scanf("%f",&score); } average=total/count; printf("%d 名学生的C 语言平均成绩:%.1f\n",count,average); return 0; } 程序运行结果1: 程序运行结果2: 例5.3 设s=1×2×3×…×n,求s 不大于400000时最大的n。 问题分析: (1)本例实际是计算前n 个自然数的乘积。即用每次的乘积(s)与400000比较,并 记录乘积次数。所以它是一个不定次数的循环,循环体(计算乘积)是否执行,由s 的值 决定。 (2)当s≤400000时,需要计算自然数的乘积,即需要执行循环体。 (3)当s>400000时,退出循环体。但此时s 已经超过400000,所以所要的n 值应 该是实际求出的n 值减1。 因此,程序可如下设计。 (1)定义所需的整型变量n存放参与乘积运算的自然数,整型变量s存放乘积,它们 初值均为1。 (2)判断条件s<=400000是否成立。若成立,则转步骤(3);若不成立,则转步骤(4)。 (3)计算每项的值n,并用该值与前n-1项的乘积进行相乘运算,回到步骤(2)。 (4)循环结束后,输出n-1的值,该值即为前n个自然数的乘积不大于400000时最 大的n。不大于400000的s值应该是退出循环时的s值除以n。 97 C 语言程序设计(第3 版·微课版) 程序如下: #include <stdio.h> int main( ) { int n=1; int s=1; while(s<=400000) { n=n+1; s=s*n; } printf("不大于400000 时最大的n 为%d\ns 值为%d\n",n-1,s/n); return 0; } 程序运行结果: 例5.4 从键盘输入一个非负整数,判断m 是不是素数。 问题分析: (1)素数是指除1以外的只能被1和其自身整除的自然数,如2、3、5、7、11都是素 数。所以,判断一个正整数m 是不是素数所采用的方法如下:用[2,m -1]的所有整数除 m ,但实际上用[2, m ]的所有整数除m 即可,只要[2, m ]中有一个数能整除m ,m 就 不是素数;若m 不能被[2, m ]中的任何一个数整除,则m 才是素数。 (2)由(1)的分析可以看出,判断一个正整数是素数还是非素数,判定的次数是不同 的,也就是说,循环次数是不固定的。因此,可以采用设置标志的循环,一旦确定了某个正 整数不是素数,就改变标志的初值。根据标志的值,即可区分素数和非素数。 (3)循环体主要是判断[2, m ]中的某个整数i 是否能整除m ,若能整除,则置标志 变量flag为1(在开始前先置flag为0)。因此,循环采用当型循环结构实现,执行循环体 的条件是i<=sqrt(m)&&flag==0的结果为真。退出循环有两种可能:一种是对于 [2, m ]的所有整数都已判断完毕,且均不能整除m ,即flag仍为0,在此情况下就认为 m 是素数;另一种是标志变量flag已改为1,这表示在[2, m ]中已发现了一个整数i 能 整除m ,即说明m 不是素数。 因此,程序可如下设计。 (1)定义所需的整型变量m,标志flag=0,循环变量i=2。 (2)从键盘输入变量m 的值(2是最小的素数)。 (3)如果m<2,输出“输入错误!”,程序结束;否则执行步骤(4)~(6)。 (4)判断条件i<=sqrt(m)&&flag==0是否成立,若成立,执行循环体;若不成 立,结束循环。 (5)在循环体中判断条件m%i==0是否成立,若成立,m 不是素数,flag=1;若不 98 素数的判断 第5 章 循环结构程序设计 成立,i++。 (6)循环结束后,判断flag==0是否成立,若成立,m是素数;若不成立,m不是素数。 程序如下: #include <math.h> #include <stdio.h> int main() { int m,flag=0,i=2; printf("请输入一个非负整数: \n"); scanf("%d",&m); if(m<2) printf("输入错误!\n"); else { while(i<=sqrt(m) && flag==0) { if(m%i==0) flag=1; //m 不是素数,修改flag 的值 else i++; } if(flag==0) printf("%d 是素数。\n",m); else printf("%d 不是素数。\n",m); } return 0; } 程序运行结果1: 程序运行结果2: 例5.5 求两个非负整数m 和n的最大公约数和最小公倍数。 问题分析: (1)两个非负整数m 和n的最大公约数一定小于或等于m 和n中的较小数,所以将 m 和n中的较小数存入变量t中。若m 不能被t整除或者n不能被t整除,则t一定不 是m 和n的最大公约数。此时,应使t的值减1,再重复上述过程,直到m 和n能同时被 t整除为止,如果m 和n是两个互质的非负整数,则t最终会减为1。 (2)两个非负整数m 和n的最小公倍数一定大于或等于m 和n中的较大数,所以将 m 和n中的较大数存入变量t中。若t不能被m 整除或者t不能被n整除,则t一定不 是m 和n的最小公倍数。此时,应使t的值增1,再重复上述过程,直到t能同时被m 和 99 C 语言程序设计(第3 版·微课版) n整除为止,如果m 和n是两个互质的非负整数,则t最终会增至m 和n的乘积。 因此,程序可如下设计。 (1)定义所需的变量m、n、t。 (2)从键盘输入变量m、n的值。 (3)将m、n中的较小数赋值给t。 (4)判断条件m%t!=0||n%t!=0是否成立。若成立,t不是最大公约数,计算t--, 重复执行步骤(4);若不成立,则说明m%t、n%t均为0,即求得最大公约数t。 (5)将m、n中的较大数赋值给t。 (6)判断条件t%m!=0||t%n!=0是否成立。若成立,t不是最小公倍数,计算t++, 重复执行步骤(6);若不成立,则说明t%m、t%n均为0,即求得最小公倍数t。 程序如下: #include <stdio.h> int main( ) { int m,n,t; scanf("%d%d",&m,&n); t=(m<=n)?m:n; while (m%t!=0||n%t!=0) //t 能否整除m、n t--; printf("最大公约数为%d\n",t); t=(m>n)?m:n; while (t%m!=0||t%n!=0) //m、n 能否整除t t++; printf("最小公倍数为%d\n",t); return 0; } 程序运行结果1: 程序运行结果2: 5.2 do…while语句 do…while语句的一般格式为 do { 循环体语句 }while(循环条件表达式); 语句的执行过程:先执行循环体语句,然后对循环条件表达式进行计算,若其值为真 100