制 作:方 斌
C语言程序设计教程郧阳师范高等专科学校计算机科学系方 斌 制作制 作:方 斌第 6章 循环结构程序设计制 作:方 斌
6.1 循环语句概述循环:反复执行称为“循环体”的程序段。
循环控制常用于数学迭代、对象遍历等问题的求解,几乎所有实用程序都包含循环。特别是在现代多媒体处理程序(图像、声音、通讯)中,循环更是必不可少。 Intel公司为了加快循环程序的执行,在 CPU硬件中加入多媒体扩展指令 MMX( Multi-Media-eXtension ); AMD在 CPU中加入
3D Now!指令。
循环结构是结构化程序三种基本结构之一。(顺序结构、分支结构)。
根据开始循环的初始条件和结束循环的条件不同,C语言中用如下语句实现循环
1、用 goto语句和 if语句构成循环。
2、用 while语句。
3、用 do-while语句。
4、用 for语句。
制 作:方 斌
6.2 goto语句及用 goto语句构成循环一般形式,goto 语句标号作 用:无条件转向“语句标号”处执行。
说 明:“语句标号”是一个标识符,它表示程序指令的地址。
goto语句不符合结构化程序设计准则,因为无条件转向使程序结构无规律、可读性差。一般应避免使用 goto语句,但如果能大大提高程序的执行效率,也可以使用。
[例 6.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的累计和。
根据已有的知识,单独实现每一步都不难。但是,由于需要经常使用这种重复计算结构(称为循环结构),C语言提供了 3条循环语句来实现,
以简化、并规范循环结构程序设计。
在C语言中,可用以下语句实现循环:
( 1)用 for语句。
( 2)用 do-while语句。
( 3)用 while语句。
制 作:方 斌用 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,所以该语句也不是必需的。
制 作:方 斌
1)求解“表达式” 。如果其值为非 0,转 2);否则转 3)。
2)执行循环体语句组,然后转 1)。
3)执行 while语句的下一条。
特点:先判“表达式(条件)”。
6.3 while语句
4,while语句
( 1)一般格式
while(表达式 )
{ 循环体语句组; }
( 2)执行过程执行过程如图所示。
制 作:方 斌
[案例 6.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、循环体中必须有使循环趋于结束的语句,否则程序进入“死循环”(不结束)。
制 作:方 斌
6.4 直到型循环 do-while语句
1.一般格式
do
{ 循环体语句组 ; }
while(表达式 ); /*本行的分号不能缺省 */
当循环体语句组仅由一条语句构成时,可以不使用复合语句形式。
2.执行过程如图所示。
( 1)执行循环体语句组。
( 2)计算“循环继续条件”表达式。如果“循环继续条件”表达式的值为非 0
(真),则转向( 1)继续执行;否则,
转向( 3)。
( 3)执行 do-while的下一条语句。
do-while循环语句的特点是:先执行循环体语句组,然后再判断循环条件。
制 作:方 斌
[案例 6.3] 用 do-while语句求解 1~ 100的累计和。
/*案例代码文件名,AL5_4.C*/
/*程序功能:求 1~ 100的累计和 */
main()
{ int i=1,sum=0; /*定义并初始化循环控制变量,以及累计器 */
do
{ 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)+....+10,其中,i由键盘输入。(用 while和 do-
while两种语句分别编程序)。
while循环程序 do-while循环程序
main() main()
{ int sum=0,i; { int sum=0,i;
scanf("%d",&i); scanf("%d",&i);
while(i <= 10) do
{ sum = sum + i; { sum = sum + i;
i++; i++;
} }while(i<= 10);
printf("%d",sum); printf("%d",sum);
} }
制 作:方 斌
6.5 for语句在 3条循环语句中,for语句最为灵活,不仅可用于循环次数已经确定的情况,也可用于循环次数虽不确定、但给出了循环继续条件的情况。
1,for语句的一般格式
for([exp1]; [exp2]; [exp3])
{ 循环体语句组; }
2,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; ) while (i<=100)
{ sum = sum + i; 相当于 { sum = sum + i;
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! */
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的累计和 */
main()
{ int i,sum=0; /*将累加器 sum初始化为 0*/
for(i=1; i<=100; i++) sum += i; /*实现累加 */
printf("sum=%d\n",sum);
} [程序演示 ]
程序运行情况如下:
sum=5050
制 作:方 斌
6.6 循环的嵌套
循环嵌套:一个循环(称为“外循环”)
的循环体内包含另一个循环(称为“内循环”)。内循环中还可以包含循环,
形成多层循环。(循环嵌套的层数理论上无限制)。
三种循环( 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();
多重循环的使用与单一循环完全相同,但应特别注意内、
外层循环条件的变化。
制 作:方 斌
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语句提前结束本次循环体的执行。
制 作:方 斌
6.8 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只影响包含它们的最内层循环,与外层循环无关。
制 作:方 斌
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
6 113.10
7 153.94
8 201.06
9 254.47
10 314.16
制 作:方 斌二,continue语句作用:提前结束本次循环体的执行,接着进行下一次循环条件的判别。
[例 6.5] 把 100~ 200之间不能被 3整除的数输出。
main()
{ int n;
for (n=100; n<=200; n++)
{ if (n%3 == 0)
continue;
printf("%d",n);
}
}
制 作:方 斌
6.9 应用举例
[例 6.6] 用以下公式计算 π的值,直到最后一项的绝对值小于 1E-6为止。
算法分析:
1、每项的分母,等于前一项分母加 2,
用 n=n+2实现,n的初值为 1。
2、每项的符号交替变化,用 s = -s实现,s的初值为 +1(第一项为正)。
3、根据 1和 2,每一项的值 t = s/n,第一项的值为 1。
制 作:方 斌
#include "math.h"
main()
{
int s;
float n,t,pi;
t = 1; pi = 0; n = 1.0; s = 1;
while((fabs(t)) >= 1E-6)
{ pi = pi + t;
n = n + 2;
s = -s;
t = s/n;
}
pi = pi * 4;
printf("pi=%10.6f\n",pi);
}
运行结果,pi=3.141397
制 作:方 斌
[例 6.7] 求 Fibonacci数列的前 40个数。该数列的生成方法为:
F1=1,F2=1,Fn=Fn-1+Fn-2( n>=3),即从第 3个数开始,每个数等于前 2个数之和。
算法设计
/*案例代码文件名,AL5_5.C*/
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个数 */
}
}
制 作:方 斌
[例 6.8] 输入一个数 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);
}
制 作:方 斌
[例 6.9] 输出 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语言实现。
作业:
6.2,6.3,6.4,6.7,6.10,6.11,6.12,6.13、
6.14,6.15