第 6章 循环结构程序设计
C 语言程序设计
2009-7-31
2
问题 1:
如何根据收入,确定一个人的纳税比例及纳税额?
当一个公司有多名员工时,如何计算每个人的纳税比例及纳税额?
提出问题:
C语言,循环语句问题 2
如何根据学生的分数判断是否及格?
如何根据全班学生的分数,分别判断他们是否及格?
2009-7-31
3本章主要内容
用 goto语句实现循环控制
while循环控制
do-while循环控制
for循环控制
循环结构中的跳转语句
循环的嵌套
循环结构程序设计举例
2009-7-31
46.2 用 goto语句实现循环
有兴趣的同学自学
不提倡使用 goto语句
注意,
goto语句能实现程序无条件转移,为编程提供了便利。但是无限制地使用,会破坏程序的结构化程度。 因此应限制使用。
2009-7-31
56.3 while循环控制
语句一般格式
while ( 表达式 ) 语句
一般为 关系 表达式或 逻辑 表达式,也可以是 C语言其他类型的合法表达式
用来控制循环体是否执行
称为 内嵌语句,
可以是基本语句、
控制语句,也可以是复合语句
是循环重复执行的部分
2009-7-31
6功能:
计算表达式的值,为非 0(逻辑真)时,重复执行 内嵌语句,每执行一次,就判断一次表达式的值,直到表达式的值为 0 时结束循环,转去执行 while后面的语句。
当表达式为真语句
N-S结构图
N
Y
流程图表 达 式 非
0?
语句循环控制条件循环体
2009-7-31
7例如:
【例 6.1】 编写程序,求 100个自然数的和即,s=1+2+3+ … +100
思路:寻找 加数 与 求和 的规律加数 i——从 1变到 100,每循环一次,使 i增 1,
直到 i的值超过 100。 i的 初值 设为 1。
求和 ——设变量 sum 存放和,循环求
sum=sum+i,直至 i超过 100。
2009-7-31
8算法和程序:
#include<stdio.h>
void main( )
{ int i,sum;
i=1; sum=0;
while (i<=100)
{ sum=sum+i;
i++;
}
printf("sum=%d\n",sum);
} 程序输出结果:
sum=5050
i,循环控制变量
sum,累加器
i=1,sum=0
当 i <= 100
sum=sum+i
i++
输出 sum
2009-7-31
9注意:
循环体如果包含一个以上的语句,应该用花括号括起来,以复合语句形式出现。
在循环体中必须有使循环趋向结束的操作,否则循环将无限进行( 死循环 )。
如果 while的 (表达式 ) 值为 0,则循环体一次也不执行 (例如当 i的初值 =101) 。
在循环体中,语句的先后位置必须符合逻辑,
否则会影响运算结果。
思考程序段的输出?
……
while (i<=100)
{ i++;
sum=sum+i; }
运行后,输出:
sum=5150
原因是什么?
2009-7-31
10
⑵ int i=0;
while ( ++i <= 100 ) ==> ++i; 判断 i<=100
sum += i;
⑶ int i=0;
while ( i++ < 100 ) ==> 判断 i<100; i++
sum += i;
⑷ int i=0;
while ( i < 100 )
sum += ++i; ==> ++i; sum+=i
不同的 while 语句形式设,sum=0;
⑴ int i=1;
while ( i <= 100 )
sum += i++; ==> sum+=i; ++i ;
运行结束后:
i,sum =?
运行结束后,
i=101,sum=5050
i=101,sum=5050
i=101,sum=5050
i=100,sum=5050
2009-7-31
11其他的 while 语句形式
while (0) {,..,}
– 由于表达式恒等于 0,所以循环体永远也不会执行,是一个逻辑 错误的语句
while (1) {,..,}
– 由于表达式恒等于 1,所以不可能通过循环控制条件来结束循环体的执行,即 死循环 。
为了保证循环正常运行,应该特别注意:
– 循环控制条件的描述
– 控制条件的初始状态(初始值)
– 循环体内部对控制条件的影响
2009-7-31
126.4 do-while语句
语句一般格式
do 语句
while ( 表达式 );
功能:
– 先执行内嵌语句 (循环体),之后计算表达式的值,不为 0(逻辑真)时,再执行循环体并判断条件,直到表达式的值为 0 结束循环,转去执行 while下面的语句。
2009-7-31
13do-while循环的算法循环体当表达式为真
N-S结构图
N
Y
循环体表达式非 0?
流程图
#include<stdio.h>
void main( )
{ int i=1,sum=0;
do
{ sum=sum+i;
i++;
} while (i<=100);
printf("%d\n",sum);
}
用 do-while语句求 100个自然数的和
2009-7-31
14do-while语句的简单应用
【例 6.2】 用辗转相除法求 m和 n的最大公约数思路:
先求 m和 n相除的余数 r
然后将 m← n,将 n← r,并判断 r( 或 n)
如果 r≠0,再重复求余数,直到 r 等于 0
时结束循环此时的 m为最大公约数
2009-7-31
15算法和程序:
#include<stdio.h>
void 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);
}
程序运行情况如下:
24,60?
12
定义 m,n,r
m<n
T F
m和 n交换
r=m%n
m=n
n=r
当 r != 0时输出最大公约数 m
2009-7-31
16While和 do-while循环的比较
while和 do-while都能实现循环控制,while
结构程序通常都可以转换成 do-while结构
区别:
– do- while 语句 先执行循环体再判断条件,循环体 至少执行一次 ;
– while 语句 先判断条件再执行循环体,
循环体有可能一次也不执行
do—while循环体中一定要有能使表达式值趋于 0的操作 (如 i++),否则会出现 死循环 。
2009-7-31
17
(1)#include<stdio.h>
void main( )
{ int i,sum;
scanf(“%d”,&i);
sum=0;
while (i<=10)
{ sum=sum+i;
i++;
}
printf("sum=%d\n",sum);
}
While和 do-while循环的比较
(2)#include<stdio.h>
void main( )
{ int i,sum;
scanf(“%d”,&i);
sum=0;
do
{ sum=sum+i;
i++;
}
while(i<=10)
printf("sum=%d\n",sum);
}
运行结果:
1↙
sum=55
再运行一次:
11↙
sum=0
运行结果:
1↙
sum=55
再运行一次:
11↙
sum=11
说明,(1)当 while后面的表达式的第一次的值为“真”时,两种循环得到的结果相同。否则,二者结果不相同。
2009-7-31
186.5 for语句
语句一般格式
for (表达式 1;表达式 2;表达式 3)
语句
功能:
–计算表达式 1的值,再 判断表达式 2,如果其值为非 0(逻辑真),则执行内嵌语句 (循环体 ),并 计算表达式 3;之后再去判断表达式 2,
一直到其值为 0时结束循环,执行后续语句。
循环初始条件 循环体循环控制条件循环变量增值
2009-7-31
19for语句的算法
N-S结构图
for (表达式 1;表达式 2;表达式 3)
语句N
Y
流程图计算表达式 1
语句计算表达式 3
表达式 2
为真? 例如:
#include<stdio.h>
void main( )
{ int i,sum;
sum=0;
for ( i=1; i<=100; i++)
sum=sum+i;
printf("sum=%d\n",sum);
}
可部分或全部省略,
但,;”不可省略
2009-7-31
20省略 for语句的表达式
⑴ 表达式 1,2,3全省略,即:
for ( ; ; )
就等同于,while (1),会无限循环( 死循环 )
注意:在省略某个表达式时,应在适当位置进行循环控制的必要操作,以保证循环的正确执行
⑵ 省略表达式 1和表达式 3,即:
for(; 表达式 2;)
就等同于,while( 表达式 2 )
⑶ 省略表达式 2,即:
for( 表达式 1; ;表达式 3)
就等同于,表达式 1; while(1){ … 表达式 3;}
2009-7-31
21例如:
⑴ 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-31
22说明:
所有用 while 语句 实现的循环都可以用
for 语句 实现。
等价于:
for(表达式 1; 表达式 2 ; 表达式 3)
语句;
表达式 1;
while ( 表达式 2)
{ 语句;
表达式 3;
}
2009-7-31
23for语句的简单应用
【例 6.3】 求 n!,即计算 p=1× 2× 3× … × n
的值。
思路:求阶乘与求累加的运算处理过程类似,只要将,+”变为,*”。
设置:
乘数 i,初值为 1,终值为 n( n是循环控制终值,需要从键盘输入)
累乘器 p,每次循环令 p = p*i
2009-7-31
24程序:
#include<stdio.h>
void 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!?
2009-7-31
25熟悉几个循环语句
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-31
266.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);
}
外循环语句内循环语句外循环体 内循环体
2009-7-31
27注意:
while,do-while,for循环语句可以并列,
也可以相互嵌套,但 要层次清楚,不能出现交叉。
多重循环程序执行时,外层循环每执行一次,内层循环都需要循环执行多次 。
例如,for(a=1;a<=10;a++)
{ for (b=0;b<=5;b++)
…… }
外循环 执行了 10次,内循环 执行 6次循环正常结束时,内循环执行了 10× 6=60次
2009-7-31
286.7 几种循环语句的比较
while和 do-while语句的 表达式 只有 一个,for语句有 三个 。
while 和 for先判断 循环条件 后执行 循环体,do-
while语句 先执行 循环体 后判断 循环条件。
while语句多用于 循环次数不定 的情况
do-while语句多用于 至少要运行一次 的情况
for语句 多用于要 赋初值 或 循环次数固定 的情况
2009-7-31
296.8 循环结构中的跳转语句
有如下三种语句实现跳转:
– continue语句
– break语句
– goto语句
在循环语句的循环体中使用,可以进行循环的流程控制
2009-7-31
30
后续语句

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

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

语句 …
表达式 2?
Y
N
continue;
for语句
2009-7-31
31例如:
⑴ 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-31
32应用举例
【例 6.4】 把 100~ 200之间能被 7整除的数,
以十个数为一行的形式输出,最后输出一共有多少个这样的数。
思路:
设变量 n,从 100变化到 200;
对每个 n进行判断,当 n不能被 7整除时,终止本次循环,否则就输出这个数;
设变量 j作为输出个数的计数器,每输出一个数就令 j++;
当输出了 10个数时(即 j%10等于 0),输出 \n
退出循环后输出 j的值。
2009-7-31
33算法和程序
#include<stdio.h>
void 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");
printf("j=%d\n",j);
}
for (n=100; n<=200; n++)
n能被 7整除
T F
终止本次循环输出 n
输出 10个数
T F
换行
2009-7-31
34
后续语句

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

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

语句 …
表达式 2?
Y
N
break;
for语句
2009-7-31
35例如:
⑴ 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-31
366.9 循环结构程序设计举例
【例 6.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-31
37算法和程序
#define N 20
#include<stdio.h>
void 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
换行
2009-7-31
38举例
【例 6.6】 判断输入的某个数 m是否为素数。
若是素数,输出,YES”,若不是,
输出,NO”。
思路:素数是指只能被 1和它本身整除的数,如
5,7,11,17,… 等。
分别用 2,3,…,m-1尝试能否整除整数 m。
如果 m能被某个 数 整除,则 m就不是素数 。
这是一种 穷举算法
设除数为 j,从 2循环到 m-1
2009-7-31
39算法和程序:
#include "math.h"
#include<stdio.h>
void 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"
2009-7-31
40程序的优化
对于 穷举法 来说,为了提高程序的效率,
就要减少 尝试次数 。
#include "math.h"
#include<stdio.h>
void 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");
}
设 m=15,15=3*5;
尝试了 15%3 后,没有必要再尝试 15%5
即,k是尝试的中点思考:如何输出 100~ 200
中所有的素数
2009-7-31
41举例
【例 6.7】 编程序求 2~ 10000以内的完全数。
完全数,一个数的因子(除了这个数本身)之和等于该数本身。
思路:
设定 i从 2变到 10000,对每个 i找到其因子和 s;
判定 i= s? 若相等,则 i为完全数,否则不是。
例如,6的 因子 是 1,2,3,因子和 1+2+3= 6
因此 6 是完全数
使用 穷举算法
用 双层循环 实现
2009-7-31
42算法和程序:
#include<stdio.h>
void 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是完全数
2009-7-31
43举例
【例 6.8】 编程序,输出以下图形。
************
****
一共有 4 行,每行由空格和星号组成:空格数按行增加,星号按行减少
变量 i 控制输出行数,从 1变化到 4
变量 j 控制输出每行的空格和星号:
– j 从 1变化到 i,每次输出一个空格
– j 从 1变化到 8-2*i+ 1,每次输出一个星号使用 双重循环 实现思路:
2009-7-31
44算法和程序:
#include<stdio.h>
void 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个字符位置,应如何修改程序?