第 5章 循环结构的程序设计
5.1 循环结构问题的提出
5.2 解决单重循环的问题
5.3 解决多重循环的问题
5.4 简单的程序调试
5.1 循环结构问题的提出在用计算机解决大量的实际问题时,
经常会遇到如下许多重复运算的问题 。
( 1) 求某一同学一学期的平均分 。 解决方法是将该同学这一学期所有考核成绩累加,再除以考核门数,就得到该生的平均分 。
( 2) 计算,1*2*3*… *n。 这是一个累乘的问题,每个乘数与前面的一个数都有固定的关系 ( 后面的数比前面的数大 1) 。
因此每次累乘的数都是前面的数加 1,方法相同,实际这是一个重复累乘的问题 。
这一类问题,重复的次数有些情况是已知的,有些情况是未知的 。 但是这些问题都带有重复性的工作,解决这类问题,
采用循环结构最为适当 。
有些问题,采用单重循环就能解决,
比如上面所举的两个例子,都可以采用单重循环;而有些问题,比如说二维表格数据输出的问题,则需要采用双重循环才能解决 。
C语言提供了三种实现循环结构的语句,它们分别是,while语句,do-while语句和 for语句,三种循环语句各有不同的特点,我们可以灵活使用 。
5.2 解决单重循环的问题
5.2.1 while循环语句
while循环语句的形式如下:
while( 表达式 ) 循环体语句
while循环语句的执行过程如图 5-1所示 。

5-
1wh
ile
语句的执行说明
( 1) 用 while语句构成的是,当型,
循环结构,它的特点是:,先判断,后执行,,如果表达式的最初值为 0,则循环体语句一次也不执行 。 只有当表达式的值为非 0时,才能执行循环体语句 。 执行完循环体语句后,再返回循环的开始部位,判断表达式的值,决定是否继续循环 。
( 2) 循环体语句只能是一条语句,如需要使用多条语句,必须采用复合语句的形式 。
( 3) 循环体内一定要有能够改变表达式的值的操作,最终使其表达式的值变为 0,
否则将形成无休止的,死,循环 。
例 5.1 求,1+2+3+… +n的累加求和的值 。
问题分析:
( 1) 我们首先需要设置一个存放累加求和的变量 sum,每一次加一个数放入变量 sum中;
( 2) 再设置一个存放加数的变量 i,
每一次累加时被加的数均需比前一个数大 1;
( 3) 最后还需设置一个结束累加的变量 n,确定累加到什么数为止 。
根据以上分析,写出源程序如下:
main ( )
{ int i,n,sum;
i=1;
sum=0;
printf (" Please input n," );
scanf ("%d",&n );
while ( i<=n ) /* 累加的数 i 小于或等于终止数 n就循环累加,否则结束循环 */
{ sum=sum+i;
i++;
}
printf ("sum=%d\n",sum );
}
说明
( 1) 存放累加求和的变量 sum,说明后必须赋初值,一般为 0,否则由于说明的变量其原有初值不确定,导致结果有误 。
( 2) 程序中 sum=sum+i; 语句是一个累加求和功能的语句,它是将变量 sum中的数值加上变量 i中的数值,求和后再放入变量 sum中,此时变量 sum中存放的数值已经变为新的数值,原有数值已被覆盖掉 。
以上程序运行情况如下:
Please input n,100↙
sum=5050
5.2.2 do-while 循环语句
do-while 循环语句的形式如下:
do
循环体语句
while ( 表达式 ) ;
do-while语句的执行过程如图 5-2所示 。
图 5-2 do-while语句的执行过程说明
( 1) 用 do-while语句构成的仍是,当型循环,结构 。 它的特点是:,先执行,
后判断,。 遇到 do关键字后,首先执行循环体语句,然后计算表达式的值,如表达式的值为非 0,则继续执行循环体语句,然后再计算表达式的值,如表达式的值为 0,
则结束循环,执行 do-while语句后面的语句 。 因此这种循环结构,最少也可以执行一次循环体语句 。
( 2) 循环体语句仍然只能是一条语句,如需要使用多条语句,必须采用复合语句的形式 。
( 3) 循环体语句中也一定要有改变表达式的值的操作,最终使其表达式的值变为 0,结束循环 。 否则将成为,死,循环 。
( 4) 在关键字 while的小括号的后面,
一定要加分号,;,,千万不能忘记,它表示 do-while语句到此结束 。
例 5,2 求,n!,即计算
1× 2× 3× … × n的值 。
源程序如下:
main ( )
{ int i,n,s;
i =1;
s =1;
printf ( "Please input n," );
scanf ("%d",&n );
do
{ s = s*i ;
/* 使用,累乘,的公式 */
i++; }
while ( i<=n);
printf ("%d!= %d\n",n,s );
}
说明
( 1) 存放累乘求和的变量 s,说明后必须赋初值,一般为 1,否则由于说明的变量其原有初值不确定,导致结果有误 。
( 2) 程序中 s = s*i; 语句是一个累乘求和功能的语句,它是将变量 s中的数值乘上变量 i中的数值,累乘后再放入变量 s中,
此时变量 s中存放的数值已经变为新的数值,
原有数值已被覆盖掉 。
以上程序运行情况如下:
Please input n,5↙
5! =120
5.2.3 for循环语句
for循环语句的形式如下:
for ( 表达式 1;表达式 2;表达式 3 )
循环体语句
for语句的执行过程如图 5-3所示 。

5-
3f
or
语句的执行过程说明
( 1) 由图 5-3可知,for循环语句的特点仍是,先判断,后执行循环体,。 遇到
for关键字,先计算表达式 1的值,然后再判断表达式 2的值,如其值为非 0,则执行循环体语句,执行完循环体语句后,再来计算表达式 3的值,然后再判断表达式 2的值 。
如其值为 0,则结束 for循环语句,执行 for
循环语句后面的语句 。
( 2) 循环体语句仍然只能是一条语句,
必要时可采用复合语句的形式 。
( 3) 此结构仍需最终使表达式 2的值变为 0,以结束循环 。 否则将会造成,死,
循环 。
( 4) for语句的表示形式相当灵活,
其中:表达式 1和表达式 3均可省略,但一定要确保表达式 2最终值等于 0。 表达式 1或表达式 3省略后,其分号,;,必须有,不能省略,即:
for ( ; 表达式 2 ; ) 循环体语句
( 5) 通常情况下:表达式 1代表循环控制变量的初值,表达式 2代表循环控制变量的终值,而表达式 3代表循环控制变量的增量,例如:求 n!,可简单表示成,s=1;
for ( i=1; i<=n; i++) s=s*i;
5.2.4 三种循环语句的比较
for循环和 while循环语句结构均是先判断循环条件,条件成立,才执行循环体,
具有,先判断,后执行,特点;而 do-
while循环语句则是先执行循环体,然后再判断循环条件,具有,先执行,后判断,
的特点 。
5.3 解决多重循环的问题
5.3.1 三种循环语句的混合嵌套问题例 5.8 求 2~ 100之间的所有素数,并输出 。
问题分析判断一个数是否是素数的方法,我们在前面已经介绍了 。 设某一个数为 a,判断该数是否为素数,就是用这个数分别被 2~
去除,如果都不能被除尽,则该数为素数,
如有一次被除尽,则该数就不是素数 。
现需求 2~ 100之间的所有素数,判断素数的方法是相同的,只要利用循环依次从 2~ 100之间取一个数,判断是否是素数,
如是素数就输出显示,不是素数就继续判断下一个数,直至判断到 100为止 。
源程序如下:
# include "math.h"
main ( )
{ int n,i,j,flag,x=0;
for ( i=2; i<=100; i++)
{ flag=1; j=2;
n=(int)sqrt((double)i );
while ( flag && j<=n )
{ if ( i%j= =0 ) flag=0;
j++;
}
if ( flag )
{ printf ("%d,",i ); x++;
if ( x%5==0 ) printf ("\n");
}
}
}
程序运行时,当 i=2或 3时,变量 j的初值也为 2,大于变量 n的值,内嵌的 while循环不执行,flag变量值为 1,输出素数 2或 3;
当 i>3时,进入内层循环,若 i为素数,flag
的值不变,仍为 1,若 i不是素数,flag的值变为 0,并立即结束内循环 。 当退出内循环后,if语句判断 flag的值为 1时,输出素数 i;
若 i不是素数,flag的值变为 0,不做输出 。
外层循环继续取下一个数,通过内层循环判断是否是素数,直到外层循环取的数 i大于 100后,结束外层循环,结束程序运行 。
通过以上例子我们看到,外层循环的目的是,每次循环分别从 2~ 100的数中取某一个数,已知循环的次数为 99次,采用
for循环比较合适;而内层循环是判断某个数是否是素数,在每一次的除法中,当某一次除法运算出现余数为 0时,表明该数不是素数,立即结束内层循环,所以内层循环次数事先难以确定,因此采用 while循环最为适当 。
在解决多重循环问题时,往往需要具体问题具体分析,根据实际问题的内容和特点,采用不同的循环结构 。 因此在解决多重循环问题时,三种循环结构并举,适合哪一种循环结构,就采用哪一种循环结构 。 读者可在实践过程中灵活使用 。
5,3,2 continue 语句和
break语句在循环中的应用
1,Continue 语句
continue语句的一般形式,continue;
该语句的功能是:结束本次循环。也就是说,不管在该语句的后面是否还有其他执行语句,遇到 continue; 语句,本次循环到此结束,接着进行下一次循环的判断。
例 5.9 将 10~ 100之内的不能被 5整除的数输出 。
源程序如下:
main ( )
{ int n;
for ( n=10; n<=100; n++ )
{ if ( n%5==0 )
continue;
printf ("%d ",n );
}
}
程序运行时,当 n能被 5整除时,将执行 continue; 语句,这次循环到此结束,
不再执行 printf ("%d",n ); 语句,只有当 n
不能被 5整除时,才执行 printf ("%d",n );
语句 。
2,Break 语句
break语句的一般形式是,break;
在循环结构中使用 break; 语句,可强制结束循环 。 不管循环条件是否成立,
都将跳出它所在的本重循环,结束本重循环的执行 。 注意:它不能跳出多重循环,
只能跳出本重循环 。
例 5.10 使用 break语句的例子 。
源程序如下:
main ( )
{ int i,s;
s=0;
for ( i=1; i<=10; i++ )
{ s=s+i;
if ( s>5 ) break;
printf ("s=%d\n",s );
}
}
此例中,如果没有 break语句,则循环将执行 10次;而含有 break语句后,当循环执行到第 3次时,i等于 3,s的值为 6,if语句的条件成立,将会执行到 break语句,于是 for循环到此结束,提前终止了循环 。
break语句只能用于循环语句和 switch
语句中 。
break语句是终止循环,而 continue语句只是结束本次循环,两条语句功能不同,
请不要混淆 。
5.4 简单的程序调试读者可能在上机操作时,遇到了一个头疼的问题,怎么修改程序也总是报错,
不知从何入手 。 这就是程序调试的问题 。
归纳起来,程序出错大致有三种情况:
编译时出错,运行时出错和运行结果不符合要求 。