第三章 C循环控制.docx
《第三章 C循环控制.docx》由会员分享,可在线阅读,更多相关《第三章 C循环控制.docx(30页珍藏版)》请在冰豆网上搜索。
第三章C循环控制
第3章 循环控制
主要内容:
本章是程序结构的三大结构之一,介绍结构化程序设计中的循环结构,即(while、do/while、for),熟练掌握其概念及使用是程序设计的基本要求。
教学要求:
⏹掌握while语句的规则及其运用
⏹掌握do-while语句的规则及其运用
⏹掌握for语句的规则及其运用
⏹掌握控制语句break和continue的运用
3.1概述
生活中,需要重复的事情很多。
譬如你我人生中的每一天,就是一个循环不息的过程,重复每一天的生活,幸好,我们每天的生活并不完全一样。
在编程中,我们经常会碰到重复进行相同或者类似操作的情况,比如要求1~10这10个自然数的和。
可能一开始很容易想到,只要写一个有9个加号的算术表达式就可以了。
确实,这没有错,也是可以做到的,但是如果要求1~100甚至1000、10000的和呢?
显然再用这种方法是不可能解决的。
我们就要用到循环结构,几乎所有的实用程序都包含循环。
循环结构是结构化程序设计的基本结构之一,它和顺序结构、选择结构共同作为各种复杂程序的基本构造单元。
因此熟练掌握选择结构和循环结构的概念及使用是程序设计的最基本的要求。
设计循环的时候要清楚三个问题:
(1)要循环执行的是什么?
(2)什么条件下执行?
(3)怎样控制循环的结束?
C语言中的循环语句主要有:
(1)while语句
(2)do-while语句
(3)for语句
(4)循环控制语句break语句和continue语句
在下面各节中将分别做介绍。
3.2while语句
while语句用来实现“当型”循环结构。
其一般形式如下:
while(表达式)
{循环体语句;}
注意:
当循环体语句只有一条时,可不需要花括号;超过一条语句时,需要加上花括号。
为了养成好的编程习惯,最好都把花括号加上。
在执行while语句时,先对条件表达式进行计算,若其值为真(非0),则执行循环体中的语句,否则跳过循环体,而执行该结构后面的语句。
在进入循环体后,每执行完一次循环体语句,将再对条件表达式进行一次计算和判断。
当发现条件表达式的值为假(0)时,便立即退出循环。
其流程图如图3-1所示。
图3-1while循环的流程图
我们用while的语法套用生活中的实际例子,可以直观地看出while的用法。
假设有一个爱哭的小娃娃,有一天她要求父母给买一条小红裙,可惜父母不同意,于是她就开始一个循环:
while(父母不给买小红裙)
{
我哭;
}
这段“代码”的意思是:
当“父母不给买小红裙”,那么,小女孩就一遍一遍地哭。
这就是我们和循环流程的第一个遭遇战。
所举的例子看似直观:
“小孩一遍遍地哭,直到父母给买裙”,但真正要用程序的语言来正确地表达出来,需要很多方面要考虑到,毕竟,程序是严谨的。
首先,一个合适的判断是否继续的条件相当重要。
小女孩要继续哭,仅仅“父母不给买小红裙”,这显示不符合事实,想想我们小时候,再会哭,最终也有累的时候,所以,要想继续哭,我们的条件有两个:
“父母不给买小红裙”并且“我还没有哭累”。
while(父母不给买小红裙&&我还没有哭累)
{
我哭;
}
其次,大多数情况下,条件需要被恰当地改变。
小女孩在不停地哭,那么她如何知道父母是否买了红裙呢?
所以,她不能只顾哭,还得在哭的间隙观察大人是否同意买裙。
至于是否哭累,我们假设小女孩有一个疲劳度,每哭一次疲劳度加1,当疲劳度到达200时,可怜的小女孩累了……
while(父母不给买小红裙&&疲劳度<200)
{
我哭;
我偷看爸妈是否同意买裙;
疲劳度++;
}
【例3-1】用while语句实现求从1到100的累加和。
先阅读源程序代码:
main()
{
inti,s=0;
i=1;
while(i<=100)
{
s=s+i;
i++;
}
printf(“\ns=%d”,s);
}
程序分析与解释:
s初始为0,然后在每一遍的循环里,它都加上i,而i则每次都在被加后,增加1。
最终,i递增到101,超过100了,这个循环也就完成了任务。
运行上面程序,输出结果为:
1到100累加和为:
5050
注意
✧while括号后面没有分号。
✧循环体如果包含一个以上的语句,应该用花括弧括起来,以复合语句形式出现。
如果不加花括弧,则while语句的范围只到while后面第一个分号处。
例如,本例中while语句若无花括弧,则while语句范围只到“s=s+i;”。
✧在循环体中应有使循环趋向于结束的语句。
例如,在本例中循环结束的条件是“i>100”,因此在循环体中应该有使i增值以最终导致i>100的语句,今用“i++;”语句来达到此目的。
如果无此语句,则i的值始终不改变,循环永不结束。
✧当型循环的循环体有可能一次都不执行(当while后面的表达式为假时)。
3.3do-while语句
do-while语句用来实现“直到型”循环结构。
其与“当型”循环不同的是,有时候要求循环体至少被执行一次,直到循环条件不满足为止。
其一般形式如下:
do
{循环体语句;}
while(表达式);
注意在“while(表达式);”后面的分号不能少。
它是这样执行的:
先执行一次指定的循环体语句,然后判别表达式,当表达式的值为非零(“真”)时,返回继续执行循环体语句,如此反复,直到表达式的值等于0为止,此时循环结束。
其流程图如图3-2所示。
图3-2do-while循环的流程图
【例3-2】用do-while语句实现求从1到100的累加和。
程序如下:
main()
{
inti,s=0;
i=1;
do
{
s=s+i;
i++;
}
while(i<=100);
printf(“%d\n”,s);
}
可以看到:
对同一个问题可以用while语句处理,也可以用do-while语句处理。
do-while语句结构可以转换成while结构。
在一般情况下,用while语句和用do-while语句处理同一问题时,若二者的循环体部分是一样的,它们的结果也一样。
但是如果while后面的表达式一开始就为假(0)时,两种循环的结果是不同的。
【例3-3】while和do-while循环的比较
(1)main()
{ints=0,i;
scanf(“%d”,&i);
while(i<=10)
{s=s+i;
i++;
}
printf(“s=%d\n”,s);
}
运行情况:
1↙
s=55
再运行一次:
11↙
s=0
(2)main()
{ints=0,i;
scanf(“%d”,&i);
do
{s=s+i;
i++;
}
while(i<=10);
printf(“s=%d\n”,s);
}
运行情况:
1↙
s=55
再运行一次:
11↙
s=11
可以看到:
当输入i的值小于或者等于10时,二者得到的结果相同。
而当i>10时,二者结果就不同了。
这是因为此时对while循环来说,一次也不执行循环体(表达式“i<=10”为假),而对do-while循环语句来说则要执行一次循环体。
可以得到结论:
当while后面的表达式的第一次的值为“真”时,两种循环得到的结果相同。
否则,二者结果不相同(指二者具有相同的循环体的情况)。
【例3-4】口令程序。
用户进入某系统,有3次键盘回答口令的机会。
3次中任何一次回答正确均可进入系统(显示“welcome!
”),否则不能进入系统(显示“sorry!
”)。
试写C程序。
(本例设口令是6位自然数123456)
【分析】本例中输入密码和判断密码操作至少要执行一次,适宜用“do-while”实现。
循环控制条件最好选择用户回答口令的次数。
技巧:
口令正确和口令输入超过3次循环都会结束,如何知道口令是否正确是本例中的一个难点。
可以采用标志法。
设一个标志变量(flag):
其值为0表示口令错误,其值为1表示口令正确,以此作为程序最后判断口令正误的依据。
表3-1例3.4中的变量表
变量名
作用
类型
值
password
每次用户回答的口令
long
键盘输入
i
回答口令的次数
int
i++
flag
口令正误标志
int
0或者1
程序源代码:
main()
{
longpassword;
inti=0,flag=0;
do
{
printf(“\npleaseinputpassword:
”);
scanf(“%d”,&password);
i++;
if(password=123456){flag=1;break:
}
}while(i<3);
if(flag==1)printf(“welcome!
”);
else
printf(“sorry!
”);/*一定是三次都答错*/
}
注意在循环体内可用break语句终止循环,用continue语句结束本次循环,开始下一次循环,这中控制形式在3.6小节将详细讲解。
3.4for语句
C语言中的for语句使用最为灵活,不仅可以用于循环次数已经确定的情况,而且可以用于循环次数确定而只给出循环结束条件的情况,它完全可以代替while语句。
其一般形式如下:
for(表达式1;表达式2;表达式3)
{
循环语句;
}
它的执行过程:
(1)先求解表达式1。
(2)求解表达式2,若其值为真(非0),则执行for语句中指定的内嵌语句,然后执行下面第(3)步。
若为假(0),则结束循环,转到第(5)步。
(3)求解表达式3。
(4)转回上面第
(2)步继续执行。
(5)循环结束,执行for语句下面的语句。
对于for语句执行过程相应的程序流程图如图3-3。
for语句最简单的应用形式也是就最易理解的形式如下:
for(循环变量赋初值;循环条件;循环变量增值)
{循环语句;}
在for循环中,一般用一个变量来控制循环次数,称为循环控制变量,简称循环变量。
只要指定了循环变量的初值、终值及每次循环增量,就可以确定循环的次数。
所以,在通常情况下,for语句中条件控制的3个表达式主要是处理循环变量,分别是赋初值(表达式1)、判断是否到达终值(表达式2)及每次循环的增量(表达式3)。
注意使用for语句时应该注意的几点:
(1)for括号内的3个表达式必须用分号(;)隔开,即使有部分表达式省略,也不能省略分号。
(2)for先判断条件后执行循环体语句,即有可能循环一次也不被执行。
如:
for(x=10;x<0;x++)s=s+x;
(3)for中的3个表达式都可以省略。
省略表达式1时,应该在for语句之前给循环变量赋初值。
省略表达式2时,即不判断循环条件(条件恒成立),循环将无终止的进行下去,成死循环,为了避免这种情况可在循环体内加if/break判断来避免。
省略表达式3时,应该在循环体内加语句来改变循环变量的值,保证循环能正常的结束。
(但尽量不要在循环体内改变循环变量的值,这样很容易影响循环的执行,除非有特殊需要)
省略表达式1和表达式3时,完全等同于while语句。
三个表达式都可以省略。
如:
for(;;)语句
例如:
for(;;)语句;
for(i=1;;i+=2)语句;
for(j=5;;)语句;
for(;i<=100;)语句;
这些for循环语句都是正确的。
(4)在循环体内可用break语句终止循环,用continue语句结束本次循环,开始下一次循环。
【例3-5】用for循环计算s=1+2+…+100
main()
{inti,s=0;
for(i=1;i<=100;i++)
s=s+i;
printf(“\ns=%d”,s);
}
【例3-6】判断一个整数是不是素数(素数是只能被自己和1整除的数)。
#include"math.h"
main()
{
intnum,i,flag=0;
scanf("%d",&num);
for(i=2;i{
flag=0;/*标志变量复位*/
if(num%i==0)
{
flag=1;
break;
}
}
if(flag==0)printf("是素数\n");
elseprintf("不是素数\n");
}
程序分析与解释:
判断素数的编程思想是:
把一个变量作为标志变量,用来标志是不是素数;循环体是从2到sqrt(num),因为如果一个数不是素数,一定能分解成num=num1*num2,它们中的最小值一定小于sqrt(num),所以循环的时候只要到sqrt(num)就可以了。
同时要注意变量复位的问题。
【例3-7】求1!
+2!
+……+n!
(n<10)
main()
{
intn,i;
longtemp=1,sn=0;/*从9!
以后,所得的值就超过了int范围*/
scanf("%d",&n);
for(i=1;i<=n;i++)
{
temp*=i;
sn+=temp;/*如果没有这一步,求的就是n!
*/
}
printf("%ld\n",sn);
}
想一想如果求1!
+3!
+5!
+……+n!
应该怎么处理呢?
【例3-8】一个整数,加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少?
程序分析:
根据题意,可在10万以内进行判断,先将该数加上100后再开平方,再加上168后再开平方,如果开方后的结果满足如下条件,即是结果。
请看程序源代码:
#include"math.h"
main()
{
longi,x,y;
for(i=1;i<100000;i++)
{x=sqrt(i+100); /*x为加上100后开方后的结果*/
y=sqrt(i+268); /*y为再加上168后开方后的结果*/
if(x*x==i+100&&y*y==i+268)
printf("\n%ld\n",i);
}
}
【例3-9】求Fibonacci数列的前40个数。
这个数列有如下特点:
第1、2两个数为1,1。
从第3个数开始,该数是前面两个数之和。
即:
F1=1(n=1)
F2=1(n=2)
Fn=Fn-1+Fn-2(n>=3)
这是一个有趣的古典数学问题:
有一对兔子,从出生后第3个月起每个月都要生一对兔子。
小兔子长到第3个月后每个月又生一兔子。
假设所有兔子都不死,问每个月的兔子的总数为多少?
表3-2兔子数的规律
第几个月
小兔子对数
中兔子对数
老兔子对数
兔子总数
1
1
0
0
1
2
0
1
0
1
3
1
0
1
2
4
1
1
1
3
5
2
1
2
5
6
3
2
3
8
7
5
3
5
13
…
…
…
…
…
不满1个月的为小兔子,满1个月不满2个月的为中兔子,满3个月以上的为老兔子。
可以看到每个月的兔子总数依次为1,1,2,3,5,8,13,。
。
。
。
这就是Fibonacci数列。
程序如下:
main()
{
longintf1,f2;
inti;
f1=1;f2=1;
for(i=1;i<=20;i++)
{
printf(“%12d%12d”,f1,f2);
if(i%2==0)
printf(“\n”);
f1=f1+f2;
f2=f2+f1;
}
}
运行结果为:
1123
581321
345589144
233377610987
1597258441816765
10946177112865746368
75025121393196418317811
51422983204013462692178309
352457857022887922746514930352
241578173908816963245986102334155
程序分析与解释:
程序中在printf函数中输出格式符用“%12ld”,而不是用“%12d”,这是由于在第23个数之后,整数值已经超过了整数的最大值32767,因此必须用“%ld”格式输出。
if语句的作用是使输出4个数后换行。
i是循环变量,当i为偶数使换行,而i每增加1就要计算和输出2个数(f1,f2),因此i每隔2换一次行相当于每输出4个数后换行输出。
3.5for循环的嵌套
在一个循环体内有包含另一个完整的循环结构,称为循环的嵌套。
内嵌的循环中还可以嵌套循环,这就是多层循环。
三种循环(while、do-while、for)可以互相嵌套。
下面几种都是合法的形式:
【例3-10】输出9*9口诀。
程序分析:
分行与列考虑,共9行9列,i控制行,j控制列。
程序源代码:
#include"stdio.h"
main()
{
inti,j,result;
printf("\n");
for(i=1;i<10;i++)
{for(j=1;j<10;j++)
{
result=i*j;
printf("%d*%d=%-3d",i,j,result);/*-3d表示左对齐,占3位*/
}
printf("\n");/*每一行后换行*/
}
}
【例3-11】统计1000以内有多少个各位数字之和是5的偶自然数。
【分析】对不确定位数的每个数x,求各位数字之和,是循环问题(while)。
又由x有500种变化可知,这也是循环。
所以本例是一个典型的二重循环。
设count表示满足条件的自然数的个数,s为某数x各位数字之和,再设a作中间变量。
用流程图描述的算法如图3-4所示。
程序代码:
#include“conio.h”
main()
{
intx,a,count=0,s;
for(x=1;x<=1
000;x++)
if(x%2==0)
{
s=0;a=x;
while(a!
=0)
{s=s+a%10;
a=a/10;
}
if(s==5){printf(“%6d”,x);count++;}
}
printf(“\ntotalcount:
%d”,count);
}
请的大家采用双重循环的其他几种嵌套格式改写本应用程序。
3.6break语句和continue语句
3.6.1break语句
break语句通常用在循环语句和switch/case语句中。
当break用于switch/case语句中时,可使程序跳出switch而执行switch后面的语句,break在switch/case中的用法已在前面介绍开关语句时的例子中讲解过,这里不再举例。
当break语句用于do-while、for、while循环语句中时,可使程序终止循环而执行循环体后面的语句,通常break语句总是与if语句联在一起。
即满足条件时便跳出循环。
【例3.12】break语句的运用。
main()
{
intsn=0,i;
for(i=1;i<=100;i++)
{
if(i==51)break;/*如果i等于51,则跳出循环*/
sn+=i;/*1+2+……+50*/
}
printf("%d\n",sn);
}
可以看出,最终的结果输出的是1+2+……+50的值。
因为在i等于51的时候,就跳出循环了。
注意:
break语句只跳出一层循环(当有循环嵌套时)
练一练将程序改写成while和do--while循环的形式。
3.6.2continue语句
continue语句的作用是跳过循环体中剩余的语句去执行下一次循环。
continue语句只用在for、while、do-while等循环体中,常与if条件语句一起使用。
【例3.13】continue语句的运用。
main()
{
intsn=0,i;
for(i=1;i<=100;i++)
{
if(i==51)continue;/*如果i等于51,则结束本次循环*/
sn+=i;/*1+2+……+50+52+……+100*/
}
printf("%d\n",sn);
}
从程序中可以看出,continue语句只是当前的值没有执行,也就是说当前的值跳过去了,接着执行下次循环。
想一想break和continue主要特点,其应用有何区别?
3.7实训三循环结构程序设计
一、实验目的
1、学习循环语句for、while和do-while语句的使用方法。
2、学习用循环语句实现各种算法,例如穷举法、迭代法等。
3、掌握break和continue语句的功能。
二、实验内容
程序设计题目:
译密码。
为使电文保密,往往按一定规律将其转换成密码,收报人再按约定的规律将其译回原文。
例如,可以按以下规律将电文变成密码:
将字母A变成字母E,a变成e,即变成其后的第4个字母,W变成A,X变成B,Y变成C,Z变成D。
如下图3.4所示。
字母按所说的规律转换,非字母字符不变。
如“China!
”转换为“Glmre!
”。
输入一行字符,要求输出其相应的密码。
三、实验步骤
1.根据所学和题目要求,我们进行问题分析后,解决此问题可依次取出字母,先判断是否大写字母或小写字母,若是,则将其值加4(变成其后的第4个字母)。
如果加4以后字符值大于‘Z’或者‘z’,则表示原来的字母在V(或者v)之后,应该按图所示的规律将它转换为A-D(或a-d)之一。
2.在稿纸上完成C程序,方框处请思考后补充完整。
#include
main()
{
charc;
while((c=getchar())!
=’\n’)
{
if((c>=’a’&&c<=’z’)||(c>=’A’&&c<=’Z’))
{
}
printf(“%c”,c);
}
}
3.进入TC集成系统,设置好有关的文件路径,源程序取名为sx-3.c。
4.录入参考代码,并存盘。
5.调试运行,观察输出结果。
6.尝试用do-while循环结构代替源代码里的while结构,观察输出结果是否相同。
7.请编制程序完成将密码转化为原文。
四、实验总结
通过本实验,加深对循环过程的理解,同时进一步感受while与do-while循环语句功能上是相通的,只不过变化了书写形式而已。
如果程序执行时进入了死循环状态,则可用组合键“ctrl+break”强行终止。
习题