第 5章 循环结构程序设计北京科技大学 计算机系
C 语言程序设计
2009-7-29
2本章主要内容
while循环控制
do-while循环控制
for循环控制
用 goto语句实现循环控制
循环结构中的跳转语句
循环的嵌套
循环结构程序设计举例
2009-7-29
35.1 while循环控制
语句一般格式
while ( 表达式 ) 语句
一般为 关系 表达式或 逻辑 表达式,也可以是 C语言其他类型的合法表达式
用来控制循环体是否执行
称为 内嵌语句,
可以是基本语句、
控制语句,也可以是复合语句
是循环重复执行的部分
2009-7-29
4功能:
计算表达式的值,为非 0(逻辑真)时,重复执行 内嵌语句,每执行一次,就判断一次表达式的值,直到表达式的值为 0 时结束循环,转去执行 while后面的语句。
当表达式为真语句
N-S结构图
N
Y
流程图表 达 式 非
0?
语句循环控制条件循环体
2009-7-29
5例如:
【例 5.1】编写程序,求 100个自然数的和即,s=1+2+3+ … +100
思路:寻找 加数 与 求和 的规律加数 i——从 1变到 100,每循环一次,使 i增 1,
直到 i的值超过 100。 i的 初值 设为 1。
求和 ——设变量 sum 存放和,循环求
sum=sum+i,直至 i超过 100。
2009-7-29
6算法和程序:
main( )
{ int i,sum;
i=1; sum=0;
while (i<=100)
{ sum=sum+i;
i++;
}
printf("sum=%d\n",sum);
}
运行 jc5_1
程序输出结果:
sum=5050
i,循环控制变量
sum,累加器
i=1,sum=0
当 i <= 100
sum=sum+i
i++
输出 sum
2009-7-29
7注意:
如果 while的 (表达式 ) 值为 0,则循环体一次也不执行 (例如当 i的初值 =101) 。
在循环体中必须有使循环趋向结束的操作,
否则循环将无限进行( 死循环 )。
在循环体中,语句的先后位置必须符合逻辑,否则会影响运算结果。
思考程序段的输出?
……
while (i<=100)
{ i++;
sum=sum+i; }
运行后,输出:
sum=5150
原因是什么?
2009-7-29
8注意(续):
为了保证循环正常运行,应该特别注意:
– 循环控制条件的描述
– 控制条件的初始状态(初始值)
– 循环体内部对控制条件的影响
2009-7-29
95.2 do-while语句
语句一般格式
do 语句
while ( 表达式 );
功能:
– 先执行内嵌语句 (循环体),之后计算表达式的值,不为 0(逻辑真)时,再执行循环体并判断条件,直到表达式的值为 0 结束循环,转去执行 while下面的语句。
2009-7-29
10do-while循环的算法循环体当表达式为真
N-S结构图
N
Y
循环体表达式非 0?
流程图
main( )
{ int i=1,sum=0;
do
{ sum=sum+i;
i++;
} while (i<=100);
printf("%d\n",sum);
}
用 do-while语句求 100个自然数的和
2009-7-29
11说明:
while和 do-while都能实现循环控制,while
结构程序通常都可以转换成 do-while结构
区别:
– do- while 语句 先执行循环体再判断条件,循环体 至少执行一次 ;
– while 语句 先判断条件再执行循环体,
循环体有可能一次也不执行
do—while循环体中一定要有能使表达式值趋于 0的操作 (如 i++),否则会出现 死循环 。
2009-7-29
12do-while语句的简单应用
【例 5.3】用辗转相除法求 m和 n的最大公约数定义 m,n,r
m<n
T F
m和 n交换
r=m%n
m=n
n=r
当 r != 0时输出最大公约数 m
2009-7-29
13算法和程序:
main( )
{ int m,n,r;
scanf("%d,%d",&m,&n);
if (m<n)
{ r=m; m=n; n=r; }
do
{ r=m%n;
m=n;
n=r;
}while(r!=0);
printf("%d\n",m);
}
运行 jc5_3
程序运行情况如下:
24,60?
12
2009-7-29
145.3 for语句
语句一般格式
for (表达式 1;表达式 2;表达式 3)
语句
功能:
–计算表达式 1的值,再 判断表达式 2,如果其值为非 0(逻辑真),则执行内嵌语句 (循环体 ),并 计算表达式 3;之后再去判断表达式 2,
一直到其值为 0时结束循环,执行后续语句。
循环初始条件循环控制条件循环体
2009-7-29
15for语句的算法
N-S结构图
for (表达式 1;表达式 2;表达式 3)
语句N
Y
流程图计算表达式 1
语句计算表达式 3
表达式 2
为真? 例如:
main( )
{ int i,sum;
sum=0;
for ( i=1; i<=100; i++)
sum=sum+i;
printf("sum=%d\n",sum);
}
可部分或全部省略,
但,;”不可省略
2009-7-29
16省略 for语句的表达式
⑴ 表达式 1,2,3全省略,即:
for ( ; ; )
就等同于,while (1),会无限循环( 死循环 )
注意:在省略某个表达式时,应在适当位置进行循环控制的必要操作,以保证循环的正确执行
⑵ 省略表达式 1和表达式 3,即:
for(; 表达式 2;)
就等同于,while( 表达式 2 )
⑶ 省略表达式 2,即:
for( 表达式 1; ;表达式 3)
就等同于,表达式 1; while(1){ … 表达式 3;}
2009-7-29
17例如:
⑴ i=1;
for ( ; i<=100; i++) sum+=i;
⑵ for (i=1; ; i++)
{ … if(i>100)…
…}
⑶ for (i=1; i<=100; )
{… i++; … }
⑷ i=1;
for ( ; ; )
{ … if(i>100) …
i++; … }
2009-7-29
18说明:
所有用 while 语句 实现的循环都可以用
for 语句 实现。
等价于:
for(表达式 1; 表达式 2 ; 表达式 3)
语句;
表达式 1;
while ( 表达式 2)
{ 语句;
表达式 3;
}
2009-7-29
19for语句的简单应用
【例 5.4】求 n!,即计算 p=1× 2× 3× … × n
的值。
思路:求阶乘与求累加的运算处理过程类似,只要将,+”变为,*”。
设置:
乘数 i,初值为 1,终值为 n( n是循环控制终值,需要从键盘输入)
累乘器 p,每次循环令 p = p*i
2009-7-29
20程序:
main( )
{ int i,n; long p;
p=1;
printf("Enter n:");
scanf("%d",&n);
for (i=1; i<=n; i++)
p = p * i;
printf("p = %ld \n",p);
} 思考:
如何输出 1!,2!,…,n!?
如何求 s =1!+ 2!+ … + n!?
运行 jc5_4
2009-7-29
21熟悉几个循环语句
while (!x) x++;
当 x=0 时,执行循环体 x++;
while ((c=getchar( )) != '\n') n=n+1;
n 称为 计数器,作用是统计输入字符的个数
while (num++<=2) ; printf("%d\n",num);
循环体是 空语句,退出循环后输出 num的值
do x*=-3; while(x>5);
先执行循环体 x*=-3,再判断条件 (x>5)
for (n=0; n<26; n++) printf("%c ",n+'A');
作用是 输出 26个大写字母
for (sum=0,i=1; i<=100; sum=sum+i,i+=2) ;
作用是 计算 100以内的奇数和
2009-7-29
22几种循环语句的比较
while和 do-while语句的 表达式 只有 一个,for语句有 三个 。
while 和 for先判断 循环条件 后执行 循环体,do-
while语句 先执行 循环体 后判断 循环条件。
while语句多用于 循环次数不定 的情况
do-while语句多用于 至少要运行一次 的情况
for语句 多用于要 赋初值 或 循环次数固定 的情况
2009-7-29
235.4 用 goto语句实现循环
有兴趣的同学自学
不提倡使用 goto语句
注意,
goto语句能实现程序无条件转移,为编程提供了便利。但是无限制地使用,会破坏程序的结构化程度。 因此应限制使用。
2009-7-29
245.5 循环结构中的跳转语句
有如下三种语句实现跳转:
– continue语句
– break语句
– goto语句
在循环语句的循环体中使用,可以进行循环的流程控制
2009-7-29
25
后续语句

continue;

Y
N表达式?
后续语句

continue;…
表达式?
Y
N
5.5.1 continue语句及应用
功能:
– 中断循环体的本次执行(即跳过循环体中尚未执行的语句),立即开始执行下一次循环。
while语句 do-while语句后续语句计算表达式 3
计算表达式 1

continue;…
表达式 2?
Y
N
for语句
2009-7-29
26例如:
⑴ int x,n=0,s=0;
while (n<10)
{ scanf("%d",&x);
if (x<0) continue;
s+=x; n++;
};
⑵ int x,n=0,s=0;
do
{ scanf("%d",&x);
if (x<0) continue;
s+=x; n++;
} while (n<10);
⑶ for (n=0,s=0; n<10; n++)
{ scanf("%d",&x);
if (x<0) continue;
s+=x;
}
2009-7-29
27应用举例
【例 5.7】把 100~ 200之间能被 7整除的数,
以十个数为一行的形式输出,最后输出一共有多少个这样的数。
for (n=100; n<=200; n++)
n能被 7整除
T F
终止本次循环输出 n
输出 10个数
T F
换行
2009-7-29
28算法和程序
main( )
{ int n,j=0;
for(n=100;n<=200;n++)
{ if (n%7!=0)
continue;
printf("%6d",n);
j++;
if (j%10==0)
printf("\n");
}
printf(" \n j=%d\n",j);
}
运行 jc5_7
2009-7-29
29
后续语句

break;…
Y
N表达式?
后续语句

break;…
表达式?
Y
N
5.5.2 循环中 break的应用
功能:
– 利用 break语句能够强迫终止本层循环,
转到后续语句执行。
while语句 do-while语句后续语句计算表达式 3
计算表达式 1

break;…
表达式 2?
Y
N
for语句
2009-7-29
30例如:
⑴ int x,n=0,s=0;
while (n<10)
{ scanf("%d",&x);
if (x<0) break;
s+=x; n++;
};
⑵ int x,n=0,s=0;
do
{ scanf("%d",&x);
if (x<0) break;
s+=x; n++;
} while (n<10);
⑶ for (n=0,s=0; n<10; n++ )
{ scanf("%d",&x);
if (x<0) break;
s+=x;
}
2009-7-29
315.6 循环的嵌套
如果循环语句的循环体内又包含了另一条循环语句,则称为循环的嵌套
例如:
#include <stdio.h>
main( )
{ int i,j;
for ( i=1; i<10; i++ )
for ( j=1; j<=i; j++ )
printf ((j==i)?"%4d\n":"%4d",i*j);
}
运行 jc5_a
外循环语句内循环语句
2009-7-29
32注意:
while,do-while,for循环语句可以并列,
也可以相互嵌套,但 要层次清楚,不能出现交叉。
多重循环程序执行时,外层循环每执行一次,内层循环都需要循环执行多次 。
例如,for(a=1;a<=10;a++)
{ for (b=0;b<=5;b++)
…… }
外循环 执行了 10次,内循环 执行 6次循环正常结束时,内循环执行了 10× 6=60次
2009-7-29
335.7 循环结构程序设计
【例 5.5】按每行输出 5个数的形式输出
Fibonacci数列的前 20项 。
思路,Fibonacci数列的前几项是,1,1,2,3,5、
8,13,21,34,… 。此数列的变化规律是:
1 ( n=1)
1 ( n=2)
fn-1+fn-2 ( n>2)
fn=
设变量 f1,f2和 f3,并为 f1和 f2赋初值 1,令
f3=f1+f2得到第 3项;
将 f1←f 2,f2←f 3,再求 f3=f1+f2得到第 4项;
依此类推求第 5项,第 6项 …
这是一种 递推算法
应采用循环实现
2009-7-29
34算法和程序
#define N 20
main( )
{ int i,f1,f2,f3;
f1=f2=1;
printf("\n%8d%8d",f1,f2);
for (i=3; i<=N; i++)
{ f3=f1+f2;
f1=f2;
f2=f3;
printf("%8d",f3);
if (i%5==0) printf("\n");
}
}
f1=1,f2=1并输出
for (i=3; i<=20; i++)
f3=f2+f1
f1=f2,f2=f3
输出 f3
输出 5个数
T F
换行运行 jc5_5
2009-7-29
35举例 2
【例 5.12】判断输入的某个数 m是否为素数。
若是素数,输出,YES”,若不是,
输出,NO”。
思路:素数是指只能被 1和它本身整除的数,如
5,7,11,17,… 等。
分别用 2,3,…,m-1尝试能否整除整数 m。
如果 m能被某个 数 整除,则 m就不是素数 。
这是一种 穷举算法
设除数为 j,从 2循环到 m-1
2009-7-29
36算法和程序:
#include "math.h"
main( )
{ int j,m,k;
printf("Enter an integer number,");
scanf("%d",&m);
for (j=2; j<=m-1; j++)
if (m%j==0) break;
printf("%d ",m);
if (j>=m)
printf("YES\n");
else
printf("NO\n");
}
输入一个数 m
for (j=2; j<=m-1; j++)
m%j==0
T F
退出循环
j>=m
T F
输出 "YES,输出 "NO"
运行 jc5_12
2009-7-29
37程序的优化
对于 穷举法 来说,为了提高程序的效率,
就要减少 尝试次数 。
#include "math.h"
main( )
{ int j,m,k;
printf("Enter an integer number,");
scanf("%d",&m);
k=sqrt(m);
for (j=2; j<=k; j++)
if (m%j==0) break;
printf("%d ",m);
if (j>=k+1) printf("YES\n");
else printf("NO\n");
}
思考:如何输出 100~ 200
中所有的素数
2009-7-29
38举例 3
【例 5.13】用牛顿迭代法求方程
2x3+4x2-7x-6=0
在 x=1.5附近的根。
思路,设 xn为一个接近 xa
的近似根,过 (xn,f(xn))
点做切线,切线方程为:
)x(f
)x(fxx
n
'
n
n1n
n1n
n
n xx
)x(f)x('f

即,
xnxn+1
x
y
0
f(x)
(xn,f(xn))
(xn+1,f(xn+1))
xa
方程的根
—牛顿迭代公式
2009-7-29
39算法基本步骤:
① 先设一个方程近似根 x0,求出 方程 f的值 和 方程导数 f1的值 ;
f=2x03+4x02-7x0-6
f1=6x02+8x0-7
② 用迭代公式 x=x0-f/f1进行迭代,求出 x比 x0要接近方程真实的根;
③ 当 |x-x0|大于某个很小的数时 (如 10-6),认为未找到,此时将 x→ x0,再次求 f,f1,并迭代,又求出一个新的更接近方程根的 x;
④ 一直到 |x-x0|≤10-6时得到方程近似根,x或 x0。
这是一种 迭代算法
用循环实现
2009-7-29
40算法和程序:
#include "math.h"
main( )
{ float x,x0,f,f1;
x=1.5;
do
{ x0=x;
f=2*x0*x0*x0+4*x0*x0-7*x0-6;
f1=6*x0*x0+8*x0-7;
x=x0-f/f1;
} while(fabs(x-x0)>1e-6);
printf("%f\n",x);
}
x赋初值
x0=x
计算 f
计算 f1
计算 x=x0-f/f1
当 |x-x0|>10-6时输出 x
运行 jc5_13
2009-7-29
41举例 4
【例 5.11】编程序求 2~ 10000以内的完全数。
完全数,一个数的因子(除了这个数本身)之和等于该数本身。
思路:
设定 i从 2变到 10000,对每个 i找到其因子和 s;
判定 i= s? 若相等,则 i为完全数,否则不是。
例如,6的 因子 是 1,2,3,因子和 1+2+3= 6
因此 6 是完全数
使用 穷举算法
用 双层循环 实现
2009-7-29
42算法和程序:
main( )
{ int i,j,s;
for (i=2; i<=10000; i++)
{ s=0;
for (j=1; j<i; j++)
if (i%j==0)
s+=j;
if (i==s)
printf("%6d\n",s);
}
}
for(i=2;i<=10000; i++)
s = 0
for (j=1; j<i; j++)
i%j==0
T F
s=s+j
i==s
T F
i是完全数运行 jc5_11
2009-7-29
43举例 5
【例 5.10】编程序,输出以下图形。
************
****
一共有 4 行,每行由空格和星号组成:空格数按行增加,星号按行减少
变量 i 控制输出行数,从 1变化到 4
变量 j 控制输出每行的空格和星号:
– j 从 1变化到 i,每次输出一个空格
– j 从 1变化到 8-2*i+ 1,每次输出一个星号使用 双重循环 实现思路:
2009-7-29
44算法和程序:
main( )
{ int i,j;
for (i=1; i<=4; i++)
{ for (j=1; j<=i; j++)
printf(" ");
for (j=1;j<=8-(2*i-1);j++)
printf("*");
printf("\n");
}
}
for (i=1; i<=4; i++)
for (j=1; j<=i; j++)
输出一个空格
for (j=1; j<=8-(2*i-1); j++)
输出一个星号换行思考:
如何输出 10行 图形?
输出图形向右 平移 20个字符位置,应如何修改程序?
运行 jc5_10