第3章循环结构.docx
《第3章循环结构.docx》由会员分享,可在线阅读,更多相关《第3章循环结构.docx(31页珍藏版)》请在冰豆网上搜索。
第3章循环结构
第三章循环结构
在程序设计中,如果需要重复执行的某些操作,就要用到循环结构。
使用循环结构编程时,首先要明确2个问题,哪些操作需要重复执行?
这些操作在什么情况下重复执行?
它们分别对应循环体和循环条件,然后就可以选用C语言提供的3种循环语句:
while、do-while、for实现循环,这写循环语句我们在第一章“1、2C语言程序设计语法”和第二章“2.6字符类型”中也都见过,而第二章2、4节的用if语句和goto语句构成“直到型(无条件转移)”也叫循环结构。
3.1while语句
while是用来实现循环的语句,而且它的适用面很广。
其一般格式为:
while(表达式)
循环语句;
其执行的流程如图3.1所示。
当表达式的值为“真”时,循环执行,直到表达式的值为“假”,循环终止并继续执行while的下一条语句。
while语句的用法:
假
(1)while语句中的表达式可以是任意合法的表达式,表达式
循环体语句只能是一条语句。
真
(2)while语句的构成简单,只有一个表达式和一条循环体语句
循环体语句,分别对应循环的两个核心要素:
循
环
条件和循环体,可以直接把循环问题的分析设
计转换为语句实现。
While的下一条语句
(3)循环的实现一般包括4部分,即初始化、条件控图3.1while语句的执行流程
制、重复的操作以及通过改变循环变量的值最终
改变条件的真假性,使循环能正常结束。
当使用while语句时,由于它只有2个
成分(表达式和循环体语句),就需要另加初始化部分,第4部分while的循环体
语句中必须包含能最终改变循环条件真假性的操作。
例3.1从键盘输入一批学生的成绩,计算平均分,并统计不及格学生的人数。
这是一个累加求和的问题,将输入的成绩先累加,最后再除以学生的数量,算出平均分。
本题的难点在于确定循环条件,由于题目中没有给出学生的数量,不知道输入数据的个数,所以无法事先确定循环次数,这时需要自己设计循环条件,可以用一个特殊的数据作为正常输入数据的结束标志,由于成绩都是正数,就选用一个负数作为结束标志,因此,循环条件就是输入的数据grade>=0。
#include
intmain()
{intnum=0,fai=0;//num记录输入数据的个数,以便统计平均分;fai记录不及格人数
doublegrade,total=0;//grade存放输入的成绩,total保存成绩之和
printf("Entergrades:
\n");//输入提示
scanf("%lf",&grade);//输入第一个学生成绩
while(grade>=0)
{total=total+grade;//累加成绩
num++;//计数
if(grade<60)fai++;//不及格人数统计
scanf("%lf",&grade);//再读入一个新数据,为下次循环做准备
}
if(num!
=0)
{printf("Gradeverageis%.2f\n",total/num);//total/num是累加成绩/成绩个数=平均分
printf(“不及格学生的人数为(failures):
%d\n”,fai);
}
else
printf("Gradeaverageis0\n");
return0;
}
例3.2猴子吃桃问题,猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个,第二天早上又将剩下的桃子吃掉一半多一个。
以后每天早上都吃了前一天剩下的一半多一个,到第10天早上想再吃时,见只剩下一个桃子了,求第一天共摘下多少桃子。
程序编写如下:
#include//第10天是1,因为4的1半是2,多1个是3,第10天是1了
main()//第9天是(1+1)*2=4(1+1)*2=4是第9天的4
{intday=9,x1,x2=1;//x1前1天数,x2后1天数//第8天是(4+1)*2=10第8天10
while(day>0)//第7天是(10+1)*2=22第7天22
{//前一天桃子数是后一天桃子数加1后的2倍//第6天是(22+1)*2=46第6天46
x1=(x2+1)*2;//第5天是(46+1)*2=94第5天94
x2=x1;//第4天是(94+1)*2=190第4天190
day--;//第3天是(190+1)*2=382第3天382
}//第2天是(382+1)*2=7661534/2-1=766是第2天
printf("total=%d\n",x1);//第1天是(766+1)*2=1534(766+1)*2=1534是第1天
return0;
}
运行结果:
total=1534(也就是猴子第一天摘的桃子是1534个)
3.2do–while语句
do–while语句与while语句略有不同,它先执行循环体,后判断循环条件。
所以无论循环条件的值如何,至少会执行一次循环体,其一般形式如下:
do
{
循环体语句
}
While(表达式);
do–while语句的执行流程如图3.2所示,第一
次进入循环时,首先执行循环体语句,然后再检查循环
控制条件,即计算表达式,若值为“真”,继续循环,直循环体语句
到表达式的值为“假”,循环结束,执行do-while的下假
一条语句。
表达式
do-while语句的使用方法和while语句类似,语句真
中的表达式可以是任意合法的表达式,循环体语句只能
是一条语句;使用时要另加初始化部分,循环体语句必须
包含能最终改变条件真假的操作,例如例3.2中的day>0do-while的下一条语句
用--day来控制,到day减到不大于0时就结束了。
图3.2do-while语句流程图
do–while语句适用于先循环,后判断循环条件
的情况,一般在循环体的执行过程中明确循环控制条件,它每执行一次循环体后,再判断条件,以决定是否进行下一次循环。
例3.3求sn=a+aa+aaa+…+aa…a之值,其中a是一个数字,例如:
3+33+333+3333+33333(此时n是5),a和n由键盘输入。
#include
main()
{//a是位上的数如3,n是多少位,如33333是5位,tn是前个位数a,sn是后个位数aa
inta,n,i=1,tn=0,sn=0,z=0;//i是用做循环的
printf("a=:
");//输进位上的一个数
scanf("%d",&a);
z=a;
printf("n=:
");//要有多少位
scanf("%d",&n);
do
{tn=tn+a;//第一次tn是0,0+a是a,之后a*10为a0,第2次tn是a,a+a*10=aa……
sn=sn+tn;
a=a*10;
++i;
}
while(i<=n);
printf("a+aa+aaa+...=%d\n",sn);
printf("%d+%d%d+%d%d%d+%d%d%d%d+.....的前%d项和是=%d\n",
z,z,z,z,z,z,z,z,z,z,n,sn);
return0;
}
运行结果:
a=:
3
n=:
5
a+aa+aaa+…=37035
3+33+333+3333+……的前5项和是:
37035
注意:
(1)循环体如果包含一个以上的语句,应该用大括弧括起来,以复合语句形式出现。
如果不加大括弧,则while语句的范围只到while后面第一个分号处。
例如,本例中while语句中若无大括弧,则while语句范围只到“tn=tn+a;”。
(2)在循环体中应有使循环趋向于结束的语句。
例如,本例中循环结束的条件是“i<=n”,因此在循环体中应该有使i增值以最终导致i>n的语句,这里用“++i;”语句来达到此目的。
如果无此语句,则i的值始终不改变,循环永不结束。
其实该例题用while语句也是一样的,大家可试试看。
一般情况下,用while语句和用do-while语句处理同一问题时,若二者的循环体部分是一样的,它们的结果也一样。
但在while后面的表达式一开始就为假(0值)时,两种循环的结果是不同的。
例如:
例3、4求1-10的累加和,用while和do-while循环比较
#include#include
main()main()
{intsum=0,i;{intsum=0,i;
scanf(“%d”,&i);scanf(“%d”,&i);
while(i<=10)do
{sum=sum+i;{sum=sum+i;
i++;i++;
}}
printf(“%d”,sum);while(i<=10);
printf(“%d”,sum);
}}
运行结果:
输入1运行结果:
输入1
5555
若输入大于10的数,结果就不一样了:
运行结果:
输入11运行结果:
输入11
011
这是因为此时对while语句循环来说,一次也不执行循环体(循环体”while(i<=10)”为假,所以结果为0,而对do-while循环来说则要执行一次循环体,因此结果得11。
可以得到结论:
当while后面的表达式的第一次的值为”真”时,两种循环得到的结果相同。
否则,二者结果不相同(指二者具有相同的循环体的情况)。
3.3for语句
第二章例2、2是把华氏温度100°F转换成相应的摄氏温度的程序;如果要求输出一张华氏-摄氏温度转换表,例如:
将华氏温度30-35°F之间的每一度都转换成相应的摄氏温度后输出,就要反复做多次温度转换计算和输出。
在重复操作的过程中,温度每增加1°F,都会使用同一个计算公式和同一个程序过程。
对于这类重复执行的问题,采用C语言的循环结构for语句,可以轻而易举地解决。
例3.5输出一张华氏-摄氏温度转换表,华氏温度取值范围是[lower,upper],每次增加1°F。
计算公式如第二章例2、2中所示。
式中,c表示摄氏温度,f表示华氏温度。
#include
intmain()
{//fahr表示华氏温度,celsius为摄氏温度,lower为华氏温度下限,upper为上限
intfahr,lower,upper;
doublecelsius;
printf("Enterlower输入华氏温度下限:
");
scanf("%d",&lower);
printf("Enterupper输入华氏温度上限:
");
scanf("%d",&upper);
printf("(fahr)华氏温度转换成(celsius)摄氏温度是:
\n");
for(fahr=lower;fahr<=upper;fahr++)
{celsius=(5.0/9.0*(fahr-32));
printf("华氏温度%d=摄氏温度%6.1lf\n",fahr,celsius);
}
}
输出结果:
Enterlower:
30
Enwerlower:
35
(fahr)华氏温度转换成(celsius)摄氏温度是:
华氏温度30=摄氏温度-1.1
华氏温度31=摄氏温度-0.6
华氏温度32=摄氏温度0.0
华氏温度33=摄氏温度0.6
华氏温度34=摄氏温度1.1
华氏温度35=摄氏温度1.7
将程序的2次输入,改成一次输入,程序如下:
#include
intmain()
{intfahr,lower,upper;
doublecelsius;
printf("输入华氏温度的下限(lower)和上限(upper):
");
scanf("%d,%d",&lower,&upper);//下限值(30)和上限(35)一起输入,中间用”,”分开。
printf("fahrcelsius:
\n");
for(fahr=lower;fahr<=upper;fahr++)
{celsius=(5.0/9.0*(fahr-32));
printf("%d%6.1lf\n",fahr,celsius);
}
}
程序设计流程如图3.3所示。
程序中用for语句实现循环,针对华氏温度在[lower,upper]内的每一个值,使用温度转换公式算出摄氏温度,并输出华氏温度和摄氏温度。
温度的转换和输出是一个重复的操作,华氏温度每次增加1°F,直到超出给定的上限upper循环结束。
for语句中的fahr++相当于fahr=fahr+1,即fahr的值增加1。
在C语言中,for语句被称为循环语句,它可以实现C语言的重复执行。
for语句的一般形式为:
for(表达式1;表达式2;表达式3)
for语句中,用两个分号分隔3个表达式,但for的后面没有分号,因为for与其后的循环语句合起来作为一条完整的语句。
for语句的执行流程如图2、3所示,先计算表达式1;再判断表达式2;若值为“真”,则执行循环体语句,并接着计算表达式3,然后继续循环;若为“假”,则结束循环,继续执行for的下一条语句。
↓↓
fahr=lower表达式1
↓↓
假
fahr<=upper?
表达式2
↓真↓
转换计算和输出循环体语句
↓↓
fahr++表达式3
for的下一条语句
图3.3例2.7程序中for语句的执行流程图图3.4for语句执行流程图
for语句中的3个表达式以及循环体语句的执行顺序和书写顺序有所不同,计算表达式3在执行循环体语句之后。
图3.4清楚地表明:
在fir语句的执行过程中。
表达式2、循环体语句和表达式3将重复执行,而表达式1只在进入循环前执行一次。
也就是说,for语句中的表达式1只执行一次。
在for语句中,常常通过改变和判断某个变量的值来控制循环的执行,这样的变量称为循环控制变量,简称循环变量。
例如:
华氏温度fahr就是循环变量,for语句的3个表达式分别对它赋初值、判断其值和改变其值。
for语句中3个表达式可以是任意合法的表达式,循环体语句只能是一条语句。
如果循环体语句由多条语句组成,必须用大括号把它们括起来,组成一条复合语句。
在C语言中,仅由一个分号(;)构成的语句称为空语句,它什么也不做。
如果将上述for语句改为:
for(fahr=lower;fahr<=upper;fahr++);//分号代表空语句
{celsius=(5.0/9.0*(fahr-32));
printf("%d%6.1lf\n",fahr,celsius);
}
则循环体语句就是空语句,真正要反复执行的温度的转换和输出都被当做for的下一条语句。
这也是初学者常犯的错误,程序运行时系统同样不会有任何出错提示。
不要在for语句中随意加分号(;)。
n
例3、6输入一个正整数n,求∑i
i=1
这是一个反复求和的过程,在数学上可以表示为:
sum=1+2+3…+n,但无法直接表示成C语言的表达式。
为了解决这个问题,首先抽取出具有共性的算式(称为循环不变式):
sum=sum+i;sum是累加和,其初值为0。
该算式重复n次,同时i从1变到n,就实现了从1加到n。
设i为循环变量,确定for语句中的3个表达式和循环体语句:
(1)指定循环起点的表达式1:
i=1
(2)给出循环条件的表达式2:
i<=n(n是循环终点)
(3)设置循环步长的表达式3:
i++
(4)循环体语句:
sum=sum+i
//计算1+2+3+…+n
#include
intmain()
{inti,n,sum;
printf("Entern:
");
scanf("%d",&n);
sum=0;
for(i=1;i<=n;i++)
{
sum=sum+i;//反复累加i的值
}
printf("Sumofnumbersfrom1to%dis%d\n",n,sum);
return0;
}
运行结果:
Entern:
100
Sumofnumbersfrom1to100is5050
虽然循环次数由输入的n决定,但就for语句而言,n的值在循环前已经决定。
由于sum=sum+i是在原累加和sum的基础上一步一步地累加i的值,所以在循环开始前,必须置为0,以保证sum在0的基础上累加,这个步骤千万不能遗漏。
循环体语句向右缩进对齐,可以明确标识循环体的范围,这和if语句的风格一致。
111
例3、7输入一个正整数n,计算1-+-+…的前n项之和
357
//计算1-1/3+1/5-1/7+…共n项之和
#include
intmain()
{intdenominator,flag,i,n;//denominator表示分母,falg是一个改变符号的标志,i,n循环次数
doubleitem,sum;//item是第i项的值,sum是累加和
printf("Entern:
");//提示
scanf("%d",&n);//输入一个整数,要计算多少项
flag=1;//表示第一项的符号
denominator=1;//表示第i项的分母,初始为1,视为1/1
sum=0;//置累加和sum的初值为0
for(i=1;i<=n;i++)
{item=flag*1.0/denominator;//计算第i项的值
sum=sum+item;//累加第i项的值
flag=-flag;//改变符号,为下一次循环做准备
denominator=denominator+2;//分母逐项加2
}
printf("sum=%f\n",sum);//输出各项的累加和
return0;
}
运行结果:
Entern:
2
sum=0.666667
3.4循环嵌套
一个循环体内又包含另一个完整的循环结构,称为循环嵌套。
内嵌的循环中还可以嵌套循环,这就是多层循环。
while语句、do-while语句、for语句都可实现循环嵌套,如:
while()for(;;)
{{
..
..
..
while()while()*
{...}{...}***
}}*****
等等。
*******
*****
例3.8打印如图3.5的图形***
#include*
voidmain()图3.5星号图形
{inti,j,k;//定义变量,用来控制循环
for(i=0;i<=3;i++)//该循环用来输出上面4行*号
{for(j=0;j<=2-i;j++)//第一次输出3个空格,第二次i加了1,输出2个空格
printf("");//显然第三次输出一个空格,第四次不输出空格
for(k=0;k<=2*i;k++)//第一次输出一个*号,第二次k加了1,输出3个*号
printf("*");//显然第三次输出5个*号,第四次输出7个*号
printf("\n");
}
for(i=0;i<=2;i++)//该循环输出下面3行*号
{for(j=0;j<=i;j++)//第一次输出1个空格,第二次输出2个空格,第三次输出3个空格
printf("");
for(k=0;k<=4-2*i;k++)//第一次i是0,输出5个*号,第二次输出3个*号,三次1个*
printf("*");
printf("\n");
}
return;
}
例3.9输出小九九
#include
main()
{inti,j;
for(i=1;i<=9;i++)
{
for(j=1;j<=i;j++)
{
printf("%d*%d=%d",j,i,j*i);
if(i==j)
printf("\n");
}
}
return0;
}
运行结果:
1*1=1
1*2=22*2=4
1*3=32*3=63*3=9
1*4=42*4=83*4=124*4=16
1*5=52*5=103*5=154*5=205*5=25
1*6=62*6=123*6=184*6=245*6=306*6=36
1*7=72*7=143*7=214*7=285*7=356*7=427*7=49
1*8=82*8=163*8=244*8=325*8=406*8=487*8=568*8=64
1*9=92*9=183*9=274*9=365*9=456*9=547*9=638*9=729*9=81
例3.9五世纪末,我国古代数学家张丘建在他编写的《算经》一书里提出一个不定方程问题,即有名的“百钱买百鸡”问题。
说:
一只公鸡值5钱,一只母鸡值3钱,三只小鸡值1钱。
用百钱买百只鸡,问公、母、小鸡各能买多少只?
我们在这里设:
公鸡、母鸡、小鸡各为x、y、z个,显然x的变化范围在0和20之间,因为百钱全买公鸡也只不过买20只,同理y的变化范围在0~34之间,所得的不定方程为:
5x+3y+z/3=100既然是不定方程,所以其解也不只是一组,程序如下:
#include
intmain()
{
intx,y,z;
for(x=0;x<=20;++x)
{
for(y=0;y<=33;++y)
{//当x=0,y=25时,z自然=75,条件if((z%3==0)&&((5*x+3*y+z/3)==100))就成立,就打印公、母、小鸡数
//再循环x=4,y=18,z自然=78,…………就成立,………
z=100-x-y;
if((z%3==0)&&((5*x+3*y+z/3)==100))
printf("