收藏 分销(赏)

第3章循环结构.doc

上传人:s4****5z 文档编号:8655673 上传时间:2025-02-24 格式:DOC 页数:20 大小:129.50KB 下载积分:10 金币
下载 相关 举报
第3章循环结构.doc_第1页
第1页 / 共20页
第3章循环结构.doc_第2页
第2页 / 共20页


点击查看更多>>
资源描述
第三章 循环结构 在程序设计中,如果需要重复执行的某些操作,就要用到循环结构。使用循环结构编程时,首先要明确2个问题,哪些操作需要重复执行?这些操作在什么情况下重复执行?它们分别对应循环体和循环条件,然后就可以选用C语言提供的3种循环语句: while、do-while 、for实现循环,这写循环语句我们在第一章“1、2 C语言程序设计语法”和第二章“2.6字符类型”中也都见过,而第二章2、4节的用if语句和goto语句构成“直到型(无条件转移)”也叫循环结构。 3.1 while 语句 while是用来实现循环的语句,而且它的适用面很广。其一般格式为: while (表达式) 循环语句; 其执行的流程如图3.1所示。当表达式的值为“真”时,循环执行,直到表达式的值为“假”,循环终止并继续执行while的下一条语句。 while语句的用法: 假 (1)while语句中的表达式可以是任意合法的表达式, 表达式 循环体语句只能是一条语句。 真 (2)while语句的构成简单,只有一个表达式和一条 循环体语句 循环体语句,分别对应循环的两个核心要素:循 环条件和循环体,可以直接把循环问题的分析设 计转换为语句实现。 While的下一条语句 (3)循环的实现一般包括4部分,即初始化、条件控 图3.1 while语句的执行流程 制、重复的操作以及通过改变循环变量的值最终 改变条件的真假性,使循环能正常结束。当使用while语句时,由于它只有2个 成分(表达式和循环体语句),就需要另加初始化部分,第4部分while的循环体 语句中必须包含能最终改变循环条件真假性的操作。 例3.1 从键盘输入一批学生的成绩,计算平均分,并统计不及格学生的人数。 这是一个累加求和的问题,将输入的成绩先累加,最后再除以学生的数量,算出平均分。本题的难点在于确定循环条件,由于题目中没有给出学生的数量,不知道输入数据的个数,所以无法事先确定循环次数,这时需要自己设计循环条件,可以用一个特殊的数据作为正常输入数据的结束标志,由于成绩都是正数,就选用一个负数作为结束标志,因此,循环条件就是输入的数据grade>=0 。 #include <stdio.h> int main() { int num=0,fai=0; //num记录输入数据的个数,以便统计平均分;fai记录不及格人数 double grade , total=0; //grade存放输入的成绩,total保存成绩之和 printf("Enter grades:\n"); //输入提示 scanf("%lf",&grade); // 输入第一个学生成绩 while( grade >= 0 ) { total = total + grade; //累加成绩 num ++; // 计数 if(grade<60) fai++; // 不及格人数统计 scanf("%lf",&grade); //再读入一个新数据,为下次循环做准备 } if(num!=0) { printf("Grade verage is %.2f\n",total/num); //total/num是累加成绩/成绩个数=平均分 printf(“不及格学生的人数为(failures):%d\n”,fai); } else printf("Grade average is 0\n"); return 0; } 例3.2 猴子吃桃问题,猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个,第二天早上又将剩下的桃子吃掉一半多一个。以后每天早上都吃了前一天剩下的一半多一个,到第10天早上想再吃时,见只剩下一个桃子了,求第一天共摘下多少桃子。程序编写如下: #include <stdio.h> // 第10天是1,因为4的1半是2,多1个是3,第10天是1了 main() // 第9天是(1+1)*2=4 (1+1)*2=4是第9天的4 { int day=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=766 1534/2-1=766是第2天 printf("total = %d\n",x1); // 第1天是(766+1)*2=1534 (766+1)*2=1534是第1天 return 0; } 运行结果:total = 1534 (也就是猴子第一天摘的桃子是1534个) 3.2 do – while 语句 do – while语句与while语句略有不同,它先执行循环体,后判断循环条件。所以无论循环条件的值如何,至少会执行一次循环体,其一般形式如下: do { 循环体语句 } While( 表达式 ); do – while语句的执行流程如图3.2所示,第一 次进入循环时,首先执行循环体语句,然后再检查循环 控制条件,即计算表达式,若值为“真”,继续循环,直 循环体语句 到表达式的值为“假”,循环结束,执行do-while的下 假 一条语句。 表达式 do-while语句的使用方法和while语句类似,语句 真 中的表达式可以是任意合法的表达式,循环体语句只能 是一条语句;使用时要另加初始化部分,循环体语句必须 包含能最终改变条件真假的操作,例如例3.2中的day>0 do-while的下一条语句 用 - -day来控制,到day减到不大于0时就结束了。 图3.2 do-while语句流程图 do – while语句适用于先循环,后判断循环条件 的情况,一般在循环体的执行过程中明确循环控制条件,它每执行一次循环体后,再判断条件,以决定是否进行下一次循环。 例3.3 求 sn = a + aa + aaa + … + aa…a 之值,其中a是一个数字,例如: 3 + 33 + 333 + 3333 + 33333(此时n是5),a和n由键盘输入。 #include <stdio.h> main() { //a是位上的数如3,n是多少位,如33333是5位,tn是前个位数a,sn是后个位数aa int a,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); return 0; } 运行结果: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 <stdio.h> #include<stdio.h> main() main() { int sum=0,i; { int sum=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 55 55 若输入大于10的数,结果就不一样了: 运行结果:输入 11 运行结果:输入 11 0 11 这是因为此时对while语句循环来说,一次也不执行循环体(循环体”while(i<=10)”为假,所以结果为0,而对do-while循环来说则要执行一次循环体,因此结果得11。 可以得到结论:当while后面的表达式的第一次的值为”真”时,两种循环得到的结果相同。否则,二者结果不相同(指二者具有相同的循环体的情况)。 3.3 for 语句 第二章例2、2是把华氏温度100°F转换成相应的摄氏温度的程序;如果要求输出一张华氏-摄氏温度转换表,例如:将华氏温度30-35°F之间的每一度都转换成相应的摄氏温度后输出,就要反复做多次温度转换计算和输出。在重复操作的过程中,温度每增加1°F,都会使用同一个计算公式和同一个程序过程。对于这类重复执行的问题,采用C语言的循环结构for语句,可以轻而易举地解决。 例3.5 输出一张华氏-摄氏温度转换表,华氏温度取值范围是[lower,upper],每次增加1°F。计算公式如第二章例2、2中所示。式中,c表示摄氏温度,f表示华氏温度。 #include < stdio.h > int main() { // fahr表示华氏温度,celsius为摄氏温度,lower为华氏温度下限,upper为上限 int fahr, lower, upper; double celsius; printf("Enter lower输入华氏温度下限:"); scanf("%d",&lower); printf("Enter upper输入华氏温度上限:"); 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); } } 输出结果: Enter lower:30 Enwer lower:35 (fahr)华氏温度转换成 (celsius)摄氏温度是: 华氏温度30 = 摄氏温度 -1.1 华氏温度31 = 摄氏温度 -0.6 华氏温度32 = 摄氏温度 0.0 华氏温度33 = 摄氏温度 0.6 华氏温度34 = 摄氏温度 1.1 华氏温度35 = 摄氏温度 1.7 将程序的2次输入,改成一次输入,程序如下: #include <stdio.h> int main() { int fahr,lower,upper; double celsius; printf("输入华氏温度的下限(lower)和上限(upper):"); scanf("%d,%d",&lower,&upper);//下限值(30)和上限(35)一起输入,中间用”,”分开。 printf("fahr celsius:\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.4 for语句执行流程图 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 <stdio.h> int main() { int i, n, sum; printf("Enter n :"); scanf("%d",&n); sum=0; for(i=1;i<=n;i++) { sum=sum+i; //反复累加i的值 } printf("Sum of numbers from 1 to %d is %d\n",n,sum); return 0; } 运行结果: Enter n: 100 Sum of numbers from 1 to 100 is 5050 虽然循环次数由输入的n决定,但就for语句而言,n的值在循环前已经决定。 由于sum = sum + i是在原累加和sum的基础上一步一步地累加i的值,所以在循环开始前,必须置为0,以保证sum在0的基础上累加,这个步骤千万不能遗漏。 循环体语句向右缩进对齐,可以明确标识循环体的范围,这和if语句的风格一致。 1 1 1 例3、7 输入一个正整数n,计算 1 - + - +…的前n项之和 3 5 7 //计算1-1/3+1/5-1/7+…共n项之和 #include <stdio.h> int main() { int denominator,flag,i,n; // denominator表示分母,falg是一个改变符号的标志,i,n循环次数 double item,sum; // item是第i项的值,sum是累加和 printf("Enter n:"); // 提示 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); // 输出各项的累加和 return 0; } 运行结果:Enter n: 2 sum = 0.666667 3.4 循环嵌套 一个循环体内又包含另一个完整的循环结构,称为循环嵌套。内嵌的循环中还可以嵌套循环,这就是多层循环。while语句、do-while语句、for语句都可实现循环嵌套,如: while () for (; ;) { { . . . . . . while () while () * { . . . } { . . . } * * * } } * * * * * 等等。 * * * * * * * * * * * * 例3.8 打印如图3.5的图形 * * * #include <stdio.h> * void main() 图3.5 星号图形 { int i, 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 <stdio.h> main() { int i,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"); } } return 0; } 运行结果: 1*1=1 1*2=2 2*2=4 1*3=3 2*3=6 3*3=9 1*4=4 2*4=8 3*4=12 4*4=16 1*5=5 2*5=10 3*5=15 4*5=20 5*5=25 1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36 1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49 1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64 1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81 例3.9 五世纪末,我国古代数学家张丘建在他编写的《算经》一书里提出一个不定方程问题,即有名的“百钱买百鸡”问题。说:一只公鸡值5钱,一只母鸡值3钱,三只小鸡值1钱。用百钱买百只鸡,问公、母、小鸡各能买多少只? 我们在这里设:公鸡、母鸡、小鸡各为x、y、z个,显然x的变化范围在0和20之间,因为百钱全买公鸡也只不过买20只,同理y的变化范围在0~34之间,所得的不定方程为: 5x + 3y + z/3 = 100 既然是不定方程,所以其解也不只是一组,程序如下: #include <stdio.h> int main() { int x,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("cock(公鸡)=%d\t hen(母鸡)=%d\t chicken(小鸡)=%d\n",x,y,z); } } return 0; } 运行结果: cock(公鸡) = 0 hen(母鸡) = 25 chicken(小鸡) = 75 cock(公鸡) = 4 hen(母鸡) = 18 chicken(小鸡) = 78 cock(公鸡) = 8 hen(母鸡) = 11 chicken(小鸡) = 81 cock (公鸡)= 12 hen(母鸡) = 4 chicken(小鸡) = 84 趣 味 游 戏 题: 和计算机比赛,设有n坐山,你和计算机各为一方,双方轮流搬山,规定每次搬的山数不超过k坐,谁搬最后一坐山,就算谁输。 游戏开始时,计算机首先打印出:“你选择要搬的山的总数”,以及“每//次允许搬山的最大数(k)",然后请你先搬,等你从键盘上输入你要搬的总数后,计算机马上又打印出它搬的山数,并告诉你还余下多少坐山,并请你再搬,这样轮流搬山,直到最后一坐山搬完为止。计算机会告诉你这局谁赢了。接着它便准备同你玩下一局。你若不想继续玩了,可以在打入山的总数时输入"0",这时计算机便告诉你共玩了几局,双方胜负如何,并结束游戏。 计算机每次搬山遵循的原则是当: 剩余山数 -1<=可移动的最大数 时就移动(剩余山数-1)坐,以便把最后一坐山留给你。 由于对任意正整数 x , y一定有: x%(y+1)<=y 因此对于我们的问题,计算机为了把最后一坐山留给你,而又要控制每次搬山数不超过最大数k,它取的数应该满足下列关系: (n-1)%(k+1) 如果这样算出的数是0,即整除无余数,就规定搬1坐,以防出问题。如果摸清计算机的这种规律,你就可以采取相应措施,争取赢它。 #include <stdio.h> #include <math.h> void main() //n是搬山总数,k是搬山最大数,x你搬多少,y表示y= (n-1)%(k+1) { int n,k,x,y,cc,pc,g;// cc记载了计算机赢的局数,pc记载了人赢的局数,g记载了第几局游戏 printf("\t 搬 山 游 戏 程 序\n"); pc=cc=0; g=1; for(;;) { printf("请你选择要搬的山的总数:\n"); scanf("%d",&n); if(n==0) break; printf("请你选择每次允许搬山的最大数:\n"); rept: scanf("%d",&k); if(k>n) { printf("超过了总数,错了!,重新输入:\n"); goto rept; } printf("\n 第 %4d 局 \n",g++); printf("============================\n\n"); do { printf("你搬多少? "); scanf("%d",&x); printf("\n"); if(x<1||x>k||x>n) { printf("你搬的数非法,重新搬!\n"); continue; } n-=x; if(n==0) { printf("***********计算机赢了!**************\n"); cc++; } else { y=(n-1)%(k+1); if(y==0) y=1; n-=y; printf("计算机搬山数是:%2d\n",y); if(n!=0) printf("还剩的山数是: %2d\n",n); else { printf("=======计算机失败了!=============\n"); pc++; } } } while(n!=0); } printf("共 玩 了 %5d局\n",cc+pc); printf("计算机赢了%4d局\n",cc); printf("你 赢 了 %5d局\n",pc); } 练 习: 1、求sum = 1 + 3 + 5 + … + 9 的和。 1 1 1 1 2、求sum = 1 + - + - + - … - 的和。 2 3 4 n 2、求半径分别为:1、3、5、7、9的各个圆的面积。 3、从键盘上输入一些数,把这些数累加起来,输出累加和。以输入-1为结束符,可用 goto语句实现。 4、计算s = 1+4+7+10+…31的累加和(习题教材29页)。 求最大公约数和最小公倍数 (1)要求用while语句编出程序 2 18 24 (2)要求用do-while编出
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 百科休闲 > 其他

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服