《C语言程序设计 》课件第5章_第1页
《C语言程序设计 》课件第5章_第2页
《C语言程序设计 》课件第5章_第3页
《C语言程序设计 》课件第5章_第4页
《C语言程序设计 》课件第5章_第5页
已阅读5页,还剩74页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第5章循环结构程序设计5.1循环的基本概念5.2while语句和do-while语句5.3for语句5.4循环的嵌套5.5几种循环的比较5.6循环中的跳转5.7基本的循环算法设计技术5.8循环程序设计实例 5.1循环的基本概念

循环结构是程序设计中一种很重要的结构。其特点是:在给定条件成立时,反复执行某程序段,直到条件不成立为止。给定的条件称为循环条件,反复执行的程序段称为循环体。

循环结构有两种形式:“当型”循环和“直到型”循环。

1.“当型”循环

判断循环控制表达式是否为“真”,如为“真”,则反复执行循环体,如为“假”,则结束循环,即“先判断,后执行”。

2.“直到型”循环

首先执行循环体,然后判断循环控制表达式,如为“假”,则反复执行循环体,直到循环控制表达式为“真”时结束循环,即“先执行,后判断”。

C语言提供了多种循环语句,可以组成各种不同形式的循环结构。

(1)while语句;

(2)do-while语句;

(3)for语句;

(4)break语句、continue语句和goto语句。 5.2while语句和do-while语句

5.2.1while语句

while语句的一般形式为

while(表达式)语句

其中:“表达式”为循环条件;“语句”为循环体。

while语句的语义是:计算表达式的值,当值为真(非0)时,执行循环体语句。while语句的执行过程可用图5-1表示。图5-1

while语句的执行过程可用

【例5.1】

用while语句计算整数1~100的和。

用传统流程图和N-S结构流程图表示算法,见图5-2。图5-2用while语句计算1~100的和的流程图程序如下:

main()

{

inti;

/*循环变量*/

intsum=0;

/*累加和清0*/

i=1;

/*循环变量i赋初值*/

while(i<=100){

sum=sum+i; /*循环变量累加到sum中*/

i=i+1; /*改变循环变量i的值*/

}

printf("%d\n",sum);

}

【例5.2】统计从键盘输入一行字符的个数。

程序如下:

#include<stdio.h>

main()

{

intn=0;

printf(“inputastring:\n”);

while(getchar()!=‘\n’)n++;

printf("%d",n);

}说明

本例程序中的循环条件为getchar()!='\n',其意义是,只要从键盘输入的字符不是回车就继续循环。循环体n++完成对输入字符个数计数,因而程序实现了对输入一行字符的字符个数计数。

使用while语句应注意以下几点:

(1)while语句中的表达式一般是关系表达式或逻辑表达式,只要表达式的值为真(非0)就可继续循环。

【例5.3】while语句中的表达式的形式。

程序如下:

main()

{

inta=0,n;

printf(“\ninputn:”);

scanf(“%d”,&n);

while(n--)

printf(“%d”,a++*2);

}

说明

本例程序将执行n次循环,每执行一次,n值减1。循环体输出表达式a++*2的值,该表达式等效于(a*2;a++)。

(2)循环体如包括一个以上的语句,则必须用“{}”括起来,组成复合语句。5.2.2

do-while语句

do-while语句的一般形式为

do

语句

while(表达式);

这个循环与while循环的不同之处在于:先执行循环中的语句,然后再判断表达式是否为真,如果为真,则继续循环,如果为假,则终止循环。因此,do-while循环至少要执行一次循环语句。

do_while语句的执行过程可用图5-3表示。图5-3

do-while语句的执行过程

【例5.4】用do-while语句实现整数1~100的和。

用传统流程图和N-S结构流程图表示算法,见图5-4。图5-4用do-while语句实现1~100的和的流程图程序如下:

main()

{

inti; /*循环变量*/

intsum=0; /*累加和清0*/

i=1; /*循环变量i赋初值*/

do{

sum=sum+i;

/*循环变量累加到sum中*/

i=i+1; /*改变循环变量i的值*/

}while(i<=100); /*注意最后的分号*/

printf("%d\n",sum);

}

说明

当有许多语句参加循环时,要用“{ }”把它们括起来。

【例5.5】while和do-while循环比较。

(1)while循环

main()

{

intsum=0,i;

scanf(“%d”,&i);

while(i<=10)

{

sum=sum+i;

i++;

}

printf("sum=%d",sum);

}

(2)do_while循环

main()

{

intsum=0,i;

scanf(“%d”,&i);

do

{

sum=sum+i;

i++;

}while(i<=10);

printf("sum=%d",sum);

}

说明

while循环和do-while循环可以用来处理同一个问题,一般可以互相代替,只不过要注意形式上的区别。 5.3

for语句

在C语言中,for语句的使用最为灵活,它完全可以取代while语句。for语句的一般形式为

for(表达式1;表达式2;表达式3)语句

for语句的执行过程如下:

(1)求解表达式1。

(2)求解表达式2。若其值为真(非0),则执行for语句中指定的内嵌语句,然后执行第(3)步;若其值为假(0),则结束循环,转到第(5)步。图5-5

for语句的执行过程

(3)求解表达式3。

(4)转回第(2)步继续执行。

(5)循环结束,执行for语句下面的一个语句。

for语句的执行过程可用图5-5表示。

for语句最简单的应用形式也是最容易理解的形式如下:

for(循环变量赋初值;循环条件;循环变量增量)语句

其中:“循环变量赋初值”总是一个赋值语句,它用来给循环控制变量赋初值;“循环条件”是一个关系表达式,它决定什么时候退出循环;“循环变量增量”定义循环控制变量每循环一次后按什么方式变化。这三个部分之间用“;”分开。例如:

for(i=1;i<=100;i++)sum=sum+i;

先给i赋初值1,判断i是否小于等于100,若是则执行语句,之后值增加1;再重新判断,直到条件为假,即i>100时,结束循环。相当于:

i=1;

while(i<=100)

{

sum=sum+i;

i++;

}

for循环中语句的一般形式相当于如下的while循环形式:

表达式1;

while(表达式2)

{

语句;

表达式3;

}

注意

(1)for循环中的“表达式1(循环变量赋初值)”、“表达式2(循环条件)”和“表达式3(循环变量增量)”都是选择项,即可以缺省,但“;”不能缺省。

(2)省略了“表达式1(循环变量赋初值)”,表示不对循环控制变量赋初值。

(3)省略了“表达式2(循环条件)”,则不做其他处理时便成为死循环。例如:

for(i=1;;i++)sum=sum+i;

相当于:

i=1;

while(1)

{sum=sum+i;

i++;}

(4)省略了“表达式3(循环变量增量)”,则不对循环控制变量进行操作,这时可在语句体中加入修改循环控制变量的语句。例如:

for(i=1;i<=100;)

{sum=sum+i;

i++;}

(5)省略了“表达式1(循环变量赋初值)”和“表达式3(循环变量增量)”。例如:

for(;i<=100;)

{sum=sum+i;

i++;}

相当于:

while(i<=100)

{sum=sum+i;

i++;}

(6)3个表达式都可以省略。例如:

for(;;)语句

相当于:

while(1)语句

(7)表达式1可以是设置循环变量的初值的赋值表达式,也可以是其他表达式。例如:

for(sum=0;i<=100;i++)sum=sum+i;

(8)表达式1和表达式3可以是一个简单表达式,也可以是逗号表达式。例如:

for(sum=0,i=1;i<=100;i++)sum=sum+i;

for(i=0,j=100;i<=100;i++,j--)k=i+j;

(9)表达式2一般是关系表达式或逻辑表达式,但也可以是数值表达式或字符表达式,只要其值非零,就执行循环体。例如:

for(i=0;(c=getchar())!=‘\n’;i+=c);

又如:

for(;(c=getchar())!=‘\n’;)

printf("%c",c);

【例5.6】用for语句实现整数1~100的和。

程序如下:

main()

{

inti;

/*循环变量*/

intsum=0;

/*累加和清0*/

for(i=1;i<=100;i++){

/*第一个表达式完成循环变量i赋初值;第三个表达式实现改变循环变量i的值*/

sum=sum+i;

/*循环变量累加到sum中*/

}

printf("%d\n",sum);

} 5.4循 环 的 嵌 套

循环嵌套是指一个循环(称为“外循环”)的循环体内包含另一个循环(称为“内循环”)。内循环中还可以包含循环,形成多层循环。循环嵌套的层数理论上无限制。

三种循环(while循环、do-while循环、for循环)可以互相嵌套。例如:注:可将循环结构整个当成一条语句来看待,那就很容易理解循环的嵌套了。

【例5.7】

打印九九乘法表。

分析:

先画出乘法表结构,然后i × j,i从1到9变化,j从1到n变化,所以是两层循环结构。

程序如下:

#include<stdio.h>

main()

{

inti,j;

for(i=1;i<=9;i++)

{

for(j=1;j<=i;j++)

printf(“%4d”,i*j);

printf(“\n”);

}

}程序运行结果:

1

2

4

3

6 9

4

8 12 16

5

10 15 20 25

6

12 18 24 30 36

7

14 21 28 35 42 49

8

16 24 32 40 48 56 64

9

18 27 36 45 54 63 72 815.5几种循环的比较

下面对while、do_while、for三种循环作一比较。

(1)三种循环(while、do-while、for)都可以用来处理同一个问题,一般可以互相代替。while循环

do-while循环

for循环表达式1; 表达式1; for(表达式1;表达式2;表达式3){while(表达式2){ do{ 循环体;循环体; 循环体; }表达式3; 表达式3;

} }while(表达式2);

(2)循环条件:while、do-while在while后面指定;for循环在“表达式3”中指定。

(3)循环初始条件:while、do-while在循环前指定;for循环在“表达式1”中指定。

(4)判断循环条件的时机:while、for循环先判断循环条件,后执行;do-while循环先执行,后判断循环条件。

(5)while、do-while、for循环均可用break语句跳出循环(结束循环),用continue语句提前结束本次循环体的执行。 5.6循环中的跳转

5.6.1break语句

break语句通常用在循环语句和开关语句中。当break用于开关语句switch中时,可使程序跳出switch而执行switch以后的语句;如果没有break语句,则将成为一个死循环而无法退出。break在switch中的用法已在前面介绍开关语句的例子中碰到,这里不再举例。

当break语句用于do-while、for、while循环语句中时,可使程序终止循环而执行循环后面的语句。通常break语句总是与if语句连在一起,即满足条件时便跳出循环。break语句的执行过程可用图5-6表示。

while(表达式1)

{…

if(表达式2)break;

}图5-6

break语句的执行过程

【例5.8】输出键盘字符,直到按回车换行,按Esc键退出。

程序如下:

main()

{

inti=0;

charc;

while(1) /*设置循环*/

{

c=‘\0’; /*变量赋初值*/

while(c!=13&&c!=27) /*键盘接收字符直到按回车或Esc键*/

{

c=getch();

printf("%c\n",c);

}

if(c==27)

break; /*判断是否按Esc键,若按则退出循环*/

i++;

printf(“TheNo.is%d\n”,i);

}

printf("Theend");

}

注意

(1)break语句对if-else的条件语句不起作用。

(2)在多层循环中,一个break语句只向外跳一层。5.6.2

continue语句

continue语句的作用是跳过循环体中剩余的语句而强行执行下一次循环。continue语句只用在for、while、do-while等循环体中,常与if条件语句一起使用,用来加速循环。continue语句的执行过程可用图5-7表示。

while(表达式1)

{…

if(表达式2)continue;

}图5-7

continue语句的执行过程

【例5.9】

输出键盘字符,直到按回车退出,忽略Esc键。

程序如下:

main()

{

charc;

while(c!=13) /*不是回车符则循环*/

{

c=getch();

if(c==0X1B)

continue; /*若按Esc键不输出便进行下次循环*/

printf(“%c\n”,c);

}

}

break语句和continue语句的区别在于:break语句的功能是跳出循环,而continue语句的功能是结束本次循环体的执行,进入下一次循环。5.6.3

goto语句

goto语句是一种无条件转移语句,与BASIC中的goto语句相似。goto语句的使用格式为

goto语句标号;

其中,“语句标号”是一个有效的标识符,这个标识符加上一个“ : ”一起出现在函数内某处,执行goto语句后,程序将跳转到该标号处并执行其后的语句。另外,语句标号必须与goto语句同处于一个函数中,但可以不在一个循环层中。通常goto语句与if条件语句连用,当满足某一条件时,程序跳到语句标号处运行。

通常不使用goto语句,主要因为它会使程序层次不清,且不易读,但在多层嵌套退出时,用goto语句则比较合理。

【例5.10】

用goto语句和if语句构成循环,计算1~100的和。

程序如下:

main()

{

inti,sum=0;

i=1;

loop:if(i<=100)

{

sum=sum+i;

i++;

gotoloop;

}

printf("%d\n",sum);

}

5.7基本的循环算法设计技术

5.7.1穷举法

设计思想:对问题的所有可能状态一一测试,直到找到解或将全部可能状态测试为止。

【例5.11】编写程序求2~10000以内的完全数。(完全数是指一个数的因子(除了这个数本身)之和等于该数本身。例如,6的因子是1、2、3,1 + 2 + 3 = 6,则6是完全数。)

分析:

(1)设定i从2变到10000,对每个i找到其因子和s;

(2)判定i = s是否成立,若相等,则i为完全数,否则i不为完全数。

N-S流程图如图5-8所示。

程序如下:

#include<stdio.h>

voidmain()

{

inti,j,s;

for(i=2;i<=10000;i++)

{

s=0;

for(j=1;j<i;j++)

{

if(i%j==0)

s=s+j;

}

if(i==s)

printf(“%6d\n”,s);

}

}图5-8

N-S流程图

【例5.12】

有30个人,每个男人吃饭花3元,每个女人花2元,每个小孩花1元,一共花了50元,男人、女人、小孩一共有几个人?(“百鸡问题”)

分析:

该问题同以下问题类似:每次可走5级、3级、2级楼梯,楼梯一共有50级,有多少种走法?每次走7级剩5级,每次走5级剩3级,每次走3级剩2级楼梯,楼梯一共有多少级?一百元兑换10元、5元、2元零钱,可以有多少种兑换方法?程序如下:

#include<stdio.h>

main()

{

intx,y,z;

for(x=0;x<=30;x++)

for(y=0;y<=30;y++)

for(z=0;z<=30;z++)

{

if((3*x+2*y+z==50)&&(x+y+z==30))

printf(“man=%d,woman=%d,children=%d\n”,x,y,z);

}

}该如何修改程序以提高效率呢?男人最多16人,女人最多25人,程序可改为

for(x=0;x<=16;x++)

for(y=0;y<=25;y++)

{

z=30-x-y;

if(3*x+2*y+z==50)

printf("man=%d,woman=%d,children=%d\n",x,y,z);

}分析:

f1为第一个数,f2为第二个数,f3为第三个数。递推公式为:f1=1,f2=1,f3=f1+f2。5.7.2递推法递推法也称为迭代法,其设计思想是:迭代是一个不断用新值取代变量的旧值,或由旧值递推出变量的新值的过程。

【例5.13】按每行输出5个数的形式输出Fibonacci数列的前40个数。已知Fibonacci数列:图5-9

N-S流程图程序如下:

#include<stdio.h>

voidmain()

{

inti;

longintf1=1,f2=1,f3;

printf(“%-10ld%-10ld”,f1,f2);

for(i=3;i<=40;i++)

{

f3=f1+f2; /*计算下一个f*/

f1=f2;

f2=f3;

printf(“%-10ld”,f3);

if(i%5==0)printf(“\n”);

}

}

【例5.14】

用牛顿迭代法求方程f(x)=2x3-4x2+3x-7=0在x=2.5附近的实根,直到满足|xn-xn-1|<10-6为止。

分析:

牛顿迭代法的基本思想如图5-10所示。图5-10牛顿迭代法的基本思想设xk是方程f(x)=0的精确解x*附近的一个猜测解,过点Pk(xk,f(xk))作f(x)的切线。该切线方程为它与x轴的交点是方程:的解,为于是由xk推出xk+1,再由xk+1推出xk+2,以此类推,这就是牛顿迭代公式。可以证明,若猜测解xk取在单根x*附近,则它恒收敛。这样,经过有限次迭代后,便可以求得符合误差要求的近似根。本题的解题思路如下:

(1)建立迭代关系式。根据牛顿迭代公式有这就是要建立的迭代关系式。

(2)给定初值。初值为x=2.5

(3)给定精度(误差)为E0。精度是迭代控制的条件,即当误差大于E0时,要继续迭代。如何计算误差呢?显然应该用 |xk+1-xk| 来表示误差,于是得到循环结构的控制条件:

fabs(xk+1-xk)>=E0程序如下:

#include“stdio.h”

#include“math.h”

main()

{

floatx=2.5,x0,f,f2;

do{

x0=x; /*保存上一个x*/

f=2*x0*x0*x0-4*x0*x0+3*x0-7; /*计算f(xn-1)*/

f2=6*x0*x0-8*x0+3; /*计算f‘(xn-1)*/

x=x0-f/f2; /*计算下一个x*/

}while(fabs(x-x0)>=10e-6);

printf("%f",x);

} 5.8循环程序设计实例

【例5.15】

用公式求π。

分析:

先设置一个double类型的参数sum作为和;每个项是正负交替的,需要一个变量作为符号标志,在 -1和1之间循环变化;分母是不断变化的,也需要一个变量记录分母。

N-S流程图如图5-11所示。图5-11

N-S流程图程序如下:

#include<math.h>

main()

{

ints;

floatn,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);

}说明

(1)要改为for结构,只要修改“while(fabs(t)>1e-6)”为“for(;fabs(t)>1e-6;)”即可。

(2)为什么“n=n+2;s=-s;”要在“t=s/n;”之前?请读者自行分析。

【例5.16】

判断m是否为素数。

N-S流程图如图5-12所示。

程序如下:

#include<math.h>

main()

{

intm,i,k;

scanf(“%d”,&m);

k=sqrt(m);

for(i=2;i<=k;i++)

if(m%i==0)break;

if(i>=k+1)

printf(“%disaprimenumber\n”,m);

else

printf("%disnotaprimenumber\n",m);

}图5-12

N-S流程图

【例5.17】

有数列2/3,4/5,6/9,10/15,…,求此数列前30项的和。

分析:

对于数列的题,首先要找出通项公式或前后项的计算关系公式,根据公式来求解。由于数列的题一般执行次数能确定,因此用for语句来编写比较方便。

此题前后项的关系是:后一项的分子是前一项的分母加1,后一项的分母是前一项的分子加分母。解题思路是用循环语句求各项,并把值累加,因为是求前30项的和,所以循环执行30次。程序如下:

#include<stdio.h>

main()

{inti=2,j=3,n,c;

floats=0;

for(n=1;n<=30;n++)

{

s=s+(float)i/j;

c=i;

i=j+1;

j=c+j;

}

printf("\n%f",s);

}说明

此题中的n与循环体中的执行语句没有数值上的联系,仅仅用于决定循环执行的次数。

【例5.18】

已知a > b > c > 0,a、b、c为整数,且a + b + c < 100,则满足1/a2 + 1/b2 = 1/c2的a、b、c共有多少组?

分析:

这是一道典型的三重嵌套循环的题目。a、b、c都是位于1到99之间的整数。编程的基本思路是:找出1到99之间的所有a、b、c的排列,查看同时满足a > b > c、a + b + c < 100、1/a2 + 1/b2 = 1/c2这三个条件的a、b、c有多少组。值得注意的是,1/a2 + 1/b2 = 1/c2这个条件并不能简单地原样照写,因为在求分数的过程中必然有四舍五入,不能得出真正的准确的结果,必须把条件变形成c2(a2 + b2) = a2b2才能得出正确的结果。程序如下:

#include<stdio.h>

main()

{longa,b,c,n=0;

for(c=1;c<=97;c++)

for(b=c+1;b<=98;b++)

for(a=b+1;a<=99;a++)

if(a+b+c<100&&c*c*(a*a+b*b)==a*a*b*b)

n++;

printf("\n%ld",n);

}特别注意,此题中变量不能定义成int型。

此题可作改进,在循环时确保a > b > c,而不需要再在if中判断。改进后的程序如下:

for(a=1;a<=99;a++)

for(b=1;b<=99;b++)

for(c=1;c<=99;c++)

if(a>b&&b>c&&a+b+c<100&&c*c*(a*a+b*b)==a*a*b*b)

n++;

【例5.19】

从键盘任意输入一个正整数,编程判断它是否是素数,若是素数,输出“Yes!”,否则输出“No!”。

判断素数的方法:除了能被1和它本身整除外,不能被其他任何整数整除。1不是素数。2是最小的素数。

分析:

把m作为被除数,把i = 2~(m - 1)依次作为除数,判断被除数m与除数i相除的结果,若都除不尽,即余数都不为0,则说明m是素数。反之,只要有一次能除尽(余数为0),则说明m存在一个1和它本身以外的另外一个因子,它不是素数。方法一:

程序如下:

#include<stdio.h>

main()

{

intnumber;

inti;

/*定义循环变量i*/

intflag=1; /*定义素数标识,初始为1*/

printf(“pleaseinputanumber:\n”);

scanf(“%d”,&number); /*从键盘输入一个整数*/

for(i=2;i<=number-1&&flag;i++){

/*查看从2至number-1之间所有整数是否能整除number*/

if(number%i==0){

flag=0;

/*如果能整除number,则说明number不是素数,存在因子,故素数标识改为0*/

}

}

printf(“\n”);

if(flag)

/*若素数标识为1,则输出是素数,否则输出不是素数*/

printf(“YES====>%disaprimenumber!\n”,number);

else

printf("NO====>%disnotaprimenumber!\n",number);

}为了减少循环次数,用数学的方法可以证明:只需用2~sqrt(m)之间的数去除m,即可得到正确的判定结果。

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论