制 作:方 斌
C语言程序设计教程郧阳师范高等专科学校计算机科学系方 斌 制作制 作:方 斌第 5章 循环结构程序设计制 作:方 斌循环语句概述循环:反复执行称为“循环体”的程序段。
循环控制常用于数学迭代、对象遍历等问题的求解,几乎所有实用程序都包含循环。
循环结构是结构化程序三种基本结构之一。(顺序结构、分支结构)。
根据开始循环的初始条件和结束循环的条件不同,C语言中用如下语句实现循环
1、用 goto语句和 if语句构成循环。
2、用 while语句。
3、用 do-while语句。
4、用 for语句。
制 作:方 斌
goto 语句及用 goto 和 if 语句构成循环一般形式,goto 语句标号作用:无条件转向“语句标号”处执行。
说明:“语句标号”是一个标识符,它表示程序指令的地址。
goto语句不符合结构化程序设计准则,因为无条件转向使程序结构无规律、可读性差。一般应避免使用 goto语句,但如果能大大提高程序的执行效率,也可以使用。
[例 6.1] 用 if语句和 goto语句构成循环,求 求 1~ 100的累计和。
制 作:方 斌
[例 5.1]
用 if语句和 goto语句构成循环,求 1~ 100的累计和。
根据已有的知识,可以用,1+2+……+100”来求解,
但显然很繁琐。现在换个思路来考虑:
首先设置一个累计器 sum,其初值为 0,利用 sum
+= n来计算( n依次取 1,2,……,100),只要解决以下 3个问题即可:
( 1)将 n的初值置为 1;
( 2)每执行 1次,sum += n”后,n增 1;
( 3)当 n增到 101时,停止计算。此时,sum的值就是 1~ 100的累计和。
制 作:方 斌用 goto语句和 if语句构成循环。使用 goto语句实现求解
1~ 100累计和的程序可以如下:
main()
{ int n=1,sum=0;
loop,sum += n; n++;
if (n<=100) goto loop;
printf(“sum=%d\n”,sum);
}
其中,loop:”为语句标号(格式:标号,语句行),其命名遵循标识符命名规则。 goto语句格式,goto 标号,
功能为:使系统转向标号所在的语句行执行。
制 作:方 斌注意,结构化程序设计方法,主张限制使用 goto语句。因为滥用 goto语句,将会导致程序结构无规律、可读性差。
另外,从功能上说,for语句可完全代替当型循环语句 while,所以该语句也不是必需的。
制 作:方 斌根据已有的知识,单独实现每一步都不难。但是,由于需要经常使用这种重复计算结构(称为循环结构),C语言提供了 3条循环语句来实现,以简化、并规范循环结构程序设计。
在C语言中,可用以下语句实现循环:
( 1)用 for语句。
( 2)用 do-while语句。
( 3)用 while语句。
制 作:方 斌
1)求解“表达式” 。如果其值为非 0,转 2;否则转 3。
2)执行循环体语句组,然后转 1)。
3)执行 while语句后的语句。
特点:先判“表达式(条件)”。
5.1 while语句
5.1.1 while语句 (当型循环 )
( 1)一般格式
while(表达式 )
{
循环体语句;
}
( 2)执行过程如图所示。
制 作:方 斌
[案例 5.2] 用 while语句求 1~ 100的累计和。
/*案例代码文件名,AL5_3.C*/
/*程序功能:求 1~ 100的累计和 */
main()
{ int i=1,sum=0; /*初始化循环控制变量 i和累计器 sum*/
while( i<=100 )
{ sum += i; /*实现累加 */
i++; /*循环控制变量 i增 1*/
}
printf(“sum=%d\n”,sum);
}
程序运行情况如下:
sum=5050
制 作:方 斌注意:
1、注意给出循环的初始条件,如本例中
,sum=0,i=1”。
2、循环体包含一个以上的语句时,用大括号括起来,形成复合语句。
3、循环体中必须有使循环趋于结束的语句,否则程序进入“死循环”(不结束)。
制 作:方 斌用计算 π 的近似值,直到最后一项的绝对值小于 10-4为止分析:
1)令 PI=π /4,则 π =4*PI;
2)每一项的分子都为 1,分母是前一分母加 2;
3)每项的符号是交替出现正负,可令前一项的符号为
t = 1,则下一项的符号为 t = -t;
4)前一项为,t*(1.0/n),则后一项就为,
(-t)*(1.0/(n+2))
例 5.2 Page52
9171513114?
制 作:方 斌程序流程示意图制 作:方 斌
#include <math.h>
void main()
{
double PI = 0,s;
int t = 1,n = 1;
s = t*1.0/n;
while(fabs(s) > 1e-4)
{
PI = PI + s;
t = -t; n = n + 2; s = t*1.0/n;
}
PI = 4*PI;
printf(“PI = %lf\n”,PI);
}
制 作:方 斌
5.2 直到型循环 do-while语句
1.一般格式
do
{ 循环体语句组 ; }
while(表达式 ); /*本行的分号不能缺省 */
当循环体语句组仅由一条语句构成时,可以不使用复合语句形式。
制 作:方 斌
2.执行过程如图所示。
( 1)执行循环体语句组。
( 2)计算“循环条件”表达式。如果“循环条件”表达式的值为非 0(真),则转向( 1)继续执行;否则,
转向( 3)。
( 3)执行 do-while的下一条语句。
do-while循环语句的特点是:先执行循环体语句组,
然后再判断循环条件。
制 作:方 斌
[案例 6.3] 用 do-while语句求解 1~ 100的累计和。
void main()
{
int i=1,sum=0; /*定义并初始化循环控制变量,以及累计器 */
do
{
sum = sum + i; /*累加 */
i++;
}while(i<=100); /*循环继续条件,i<=100*/
printf(“sum=%d\n”,sum);
}
制 作:方 斌
do-while语句比较适用于处理:不论条件是否成立,先执行 1次循环体语句组的情况。除此之外,do-while语句能实现的,for语句也能实现,而且更简洁。
制 作:方 斌注意:
1、上面的流程图中循环条件是“当 i≤100时循环”,N-S
图中的条件是“循环直到 i>100”,这两者是等同的。
2、同一个问题,既可以用 while循环处理,也可以用 do-
while循环处理。
do-while处理 while处理制 作:方 斌在一般情况下,用 while和 do-while语句解决同一问题时,若二者的循环体部分是一样的,它们的结果也一样。但当 while后面的“表达式”一开始就为“假”
时,两种循环的结果不同。这是因为此时 while循环的循环不被执行,而 do-while循环的循环体被执行一次。
[例 6.4] 求 i+(i+1)+(i+2)+....+(i+10),其中,i
由键盘输入。(用 while和 do-while两种语句分别编程序)。
制 作:方 斌
while循环程序
void main()
{
int sum=0,k=0;
int i,m;
scanf("%d",&i);
while(k <= 10)
{
m = i + k;
sum = sum + m;
k++;
}
printf("%d",sum);
}
do-while循环程序
void main()
{
int sum=0,k = 0;
int i,m;
scanf("%d",&i);
do
{
m = i + k;
sum = sum + m;
k++;
}while(k<= 10);
printf("%d",sum);
}
制 作:方 斌
5.3 for语句构成的循环在 3种循环语句中,for语句最为灵活,不仅可用于循环次数已经确定的情况,也可用于循环次数虽不确定、
但给出了循环继续条件的情况。
1,for语句的一般格式
for([exp1]; [exp2]; [exp3])
{
循环体语句;
}
制 作:方 斌
for语句的执行过程
( 1)求解,exp1”表达式。
( 2)求解,exp2”表达式。
如果其值非 0,执行( 3);
否则,转至( 4)。
( 3)执行循环体语句,然后求解,exp3”表达式,然后转向( 2)。
( 4)执行 for语句的下一条语句。
制 作:方 斌一般:在 for语句中
“表达式 1”设置循环初始条件
“表达式 2”判别循环条件
“表达式 3”修改循环条件例,for(i=1;i<=100;i++) sum = sum + i;
这里,循环条件由变量 i设定,变量 i称为“循环变量”。
“表达式 1”,i=1,循环初始条件。
“表达式 2”,i<=100,循环条件。
“表达式 3”,i++,修改循环条件。
这是 for语句的典型用法:已知循环次数。(本例 100次)。
制 作:方 斌
for语句使用非常灵活,可以省略“表达式 1”、
“表达式 2”、“表达式 3”中的几个或全部表达式。
1,for语句省略“表达式 1”。“表达式 1”的作用是设定循环初始条件,“表达式 1”省略后,应在
for语句前面设置循环初始条件。例、
for(; i<=100; i++) sum = sum + i;
/* 注意,“表达式 1”后面的分号不能省略 */
制 作:方 斌
2,for语句中,如果省略“表达式 2(循环条件)”,不判别循环条件,认为循环循环条件始终为“真”,循环将无终止地进行下去。例
for(i=1;; i++) sum = sum + i;
/*,表达式 2”被省略。 */
相当于:
i = 1;
while (1)
{
sum = sum + i;
i++;
}
制 作:方 斌
3、“表达式 3(修改循环条件)”也可以省略,
但程序应在循环体(“语句”)中修改循环条件,以保证循环能正常结束。例、
for(sum=0,i=1; i<=100; )
{
sum = sum + i;
i++;
}
制 作:方 斌
4、省略“表达式 1”和“表达式 3”,只有“表达式 2”。例、
for(; i<=100; )
{
sum = sum + i;
i++;
} 相当于
while (i<=100)
{
sum = sum + i;
i++;
}
制 作:方 斌
5、“表达式 1”、“表达式 2”、“表达式 3”均省略。例、
for(;; )语句,相当于 while(1) 语句 ;
这是一种简单的死循环形式。
制 作:方 斌
6,for语句的其他变形。
例 1,for(sum=0; i<=100; i++) sum = sum + i;
例 2:for(sum=0,i=1; i<=100; i++) sum = sum+i;
例 3,for(i=0,j=100; i<=j; i++,j--) k = i + j;
例 4,for(i=0; (c=getchar()) != '\n'; i += c);
例 4的执行情况:
制 作:方 斌
3.说明
( 1),exp1”、,exp2”和,exp3”部分均可缺省,甚至全部缺省,但其间的分号不能省略。
( 2)当循环体语句仅由一条语句构成时,可以不使用复合语句形式,如上例所示。
( 3),exp1”表达式,既可以是给循环变量赋初值的赋值表达式,也可以是与此无关的其它表达式 (如逗号表达式 )
例如,for(sum=0; i<=100; i++) sum += i;
for(sum=0,i=1; i<=100; i++) sum += i
( 4),exp2”部分是一个逻辑量,除一般的关系(或逻辑)
表达式外,也允许是数值(或字符)表达式。
制 作:方 斌
[案例 ] 求 n的阶乘 n!( n!=1*2*……*n)。
/*案例代码文件名,AL5_2.C*/
/*程序功能:求 n! */
void main()
{ int i,n;
long fact=1; /*将累乘器 fact初始化为 1*/
printf(“Input n:,);
scanf(“%d”,&n);
for(i=1; i<=n; i++) fact *= i; /*实现累乘 */
printf("%d ! = %ld\n",n,fact);
}
制 作:方 斌程序运行情况如下:
Input n,5↙
5 ! = 120
制 作:方 斌
[案例 ] 求 1~ 100的累计和。
/*案例代码文件名,AL5_1.C*/
/*程序功能:求 1~ 100的累计和 */
void main()
{ int i,sum=0; /*将累加器 sum初始化为 0*/
for(i=1; i<=100; i++) sum += i; /*实现累加 */
printf("sum=%d\n",sum);
}
程序运行情况如下:
sum=5050
制 作:方 斌
5.4 循环的嵌套
循环嵌套:一个循环(称为“外循环”)的循环体内包含另一个循环(称为“内循环”)。
内循环中还可以包含循环,形成多层循环。
(循环嵌套的层数理论上无限制)。
三种循环( while循环,do-while循环,for循环)可以互相嵌套。例、
制 作:方 斌
( 1)
while()
{┆
while()
{...}
}
(2)
do
{ ┆
do
{...}
while();
}
while();
(3)
for(;;)
{ ┆
for(;;)
{...}
}
(5)
while()
{ ┆
do
{....}
while();

}
(4)
for(;;)
{ ┆
while()
{....}

}
(6)
do
{

for(;;)
{....}

}
while();
多重循环的使用与单一循环完全相同,但应特别注意内、
外层循环条件的变化。
制 作:方 斌
5.5 break语句与 continue语句为了使循环控制更加灵活,C语言提供了 break语句和 continue语句。
1.一般格式,break;
continue;
2.功能
( 1) break:强行结束本层循环,转向执行循环语句的下一条语句。
( 2) continue:对于 for循环,跳过循环体其余语句,转向循环变量增量表达式的计算;对于 while
和 do-while循环,跳过循环体其余语句,但转向循环继续条件的判定。
制 作:方 斌
3.说明
( 1) break能用于循环语句和 switch语句中,continue只能用于循环语句中。
( 2)循环嵌套时,break和 continue只影响包含它们的最内层循环,与外层循环无关。
制 作:方 斌
6.7 几种循环的比较
1、四种循环( while,do-while,for,goto)可以互相替换,
但应尽量少用 goto。
2、循环条件,while,do-while在 whie后面指定; for循环在
“表达式 3”中指定。
3、循环初始条件,while,do-while在循环前指定; for循环在“表达式 1”中指定。
4、判循环条件的时机,while,for循环先判循环条件,后执行; do-while循环先执行,后判循环条件。
5,while,do-while,for循环均可用 break语句跳出循环 (结束循环 ),用 continue语句提前结束本次循环体的执行。
制 作:方 斌
4,break和 continue语句对循环控制的影响如图所示。
continue语句结束本次循环体的执行,进入下一次循环break语句跳出循环制 作:方 斌例、
for(r=1; r<=10; r++)
{ area = pi*r*r;
if (area > 100) break;
printf("%f",aera);
}
运行结果:
r aera
1 3.14
2 12.57
3 28.27
4 50.27
5 78.54
制 作:方 斌二,continue语句作用:提前结束本次循环体的执行,接着进行下一次循环条件的判别。
[例 6.5] 把 100~ 200之间不能被 3整除的数输出。
main()
{ int n;
for (n=100; n<=200; n++)
{ if (n%3 == 0)
continue;
printf("%d",n);
}
}
制 作:方 斌
5.6 应用举例
[例 5.10] 求 Fibonacci数列的前 40个数。该数列的生成方法为,F1=1,F2=1,Fn=Fn-1+Fn-2( n>=3),
即从第 3个数开始,每个数等于前 2个数之和。
算法设计制 作:方 斌
main()
{ long int f1=1,f2=1; /*定义并初始化数列的头 2个数 */
int i=1; /*定义并初始化循环控制变量 i*/
for( ; i<=20; i++ ) /*1组 2个,20组 40个数 */
{ printf(“%15ld%15ld”,f1,f2); /*输出当前的 2个数 */
if(i%2==0) printf(“\n”); /*输出 2次( 4个数),换行 */
f1 += f2; f2 += f1; /*计算下 2个数 */
}
}
制 作:方 斌例 5.11
用迭代法求某正整数 a的平方根。已知求平方根的迭代公式为:
)
0
0(
2
1
x
a
xx
直到两项差的结果小于 1e-5为止制 作:方 斌
[例 5.12] 输入一个数 m,判其是否为“素数”。
素数( prime):又称质数,是大于 1的整数,除了能被自身和 1整除外,不能被其它正整数整除。
算法:
判断一个数 n是否为素数的方法是用 2,3,4,…,n-1去除该数,如果有其中有一个数能被 n除尽 (余数为 0),
则该数不为素数,如果一直到 n-1都不能被 n除尽则该数就为素数。
改进算法:
(1)用 2,3,4,…,n/2去除 n
(2)用 2,3,4,…,去除 nn
制 作:方 斌程序:
#include "math.h"
main()
{
int m,i,k;
scanf("%d",&m); /* 输入一个整数 m */
k = sqrt(m);
for(i=2;i<=k;i++)
if (m%i == 0) break;
if (i > k+1) printf("%d 是素数 \n",m);
else printf("%d 不是素数 \n",m);
}
制 作:方 斌
[例 ] 输出 10~ 100之间的全部素数。
算法设计要点:
( 1)显然,只要设计出判断某数 n是否是素数的算法,外面再套一个 for循环即可。
( 2)判断某数 n是否是素数的算法:根据素数的定义,用 2~( n-1)之间的每一个数去整除 n,如果都不能被整除,则表示该数是一个素数。
判断一个数是否能被另一个数整除,可通过判断它们整除的余数是否为 0来实现。
参考源程序如下:
制 作:方 斌
main()
{ int i=11,j,counter=0; /*counter用于累计素数的个数 */
for( ; i<=100; i+=2) /*外循环为内循环提供一个整数 */
{ for(j=2; j<=i-1; j++) /*内循环:判断整数 i是否是素数 */
if(i%j= =0) break;
/*i不是素数则强行结束内循环,执行下面的 if语句 */
if(counter%10= =0) /*每输出 10个数换一行 */
printf(“\n”);
if( j >= i ) /*整数 i是素数:输出,计数器加 1*/
{ printf(“%6d”,i);
counter++;
}
}
}
思考题,外循环控制变量 i的初值从 11开始、增量为 2的作法有什么好处?为提高运行速度,如何优化内循环?(提示:从减少计算次数角度来考虑)
制 作:方 斌
[小结 ] 从以上几个例子可以看到,程序设计中的关键环节有:
1、算法。如求 π值的算法、求 Fibonicci数列的算法、验证素数的算法、
字符的 ASCII码间的关系。
算法分析是程序设计中的第一个步骤,也是最重要的步骤。
2、框图。根据算法的要求,列出程序实现的步骤。
框图是保证程序正确性的重要手段,它可以避免程序分支错误或分支遗漏。复杂的算法必须画出框图。
3、程序设计环境。如操作系统的特征、键盘输入的特点(如,仅在按回车键后输入的字符才进入程序缓冲区)、开发系统环境(如
#include的使用)等。
4、程序设计的方法(结构化、面向对象)和风格(如适当的缩进)。
5、语言。注意语法规定。如 while,do-while,for语句的执行流程和特点,break,continue语句的作用等。
程序 = 算法 + 数据结构 + 程序设计方法 + 语言工具和环境制 作:方 斌本章要求及作业要求:
1、初步熟悉用计算机解决问题的思路。
2、掌握 while,do-while,for语句的特点和使用方法。
3、掌握 break,continue语句的用法。
4、熟悉一些常见问题的算法及其 C语言实现。
作业:
5.17 5.18 5.19 5.20