高级程序语言设计循环结构程序设计.ppt
第6章:循环结构程序设计,学习的意义,许多实际问题中往往需要有规律地重复某些操作,如菜谱中可以有:“打鸡蛋直到泡沫状”这样的步骤,也就是说,在鸡蛋没有打成泡沫状时要反复地打。相应的操作在计算机程序中就体现为某些语句的重复执行,这就时所谓的循环。,下面来思考一个问题:如何编程来计算1+2+3+100?,程序如下:int s=0;s=s+1;s=s+2;s=s+3;s=s+100;printf(“s=%d”,s);,重复100次,晕!,有没有更好的方法来计算呢?,有!就是用循环来编程。,While、do-while、for语句 循环嵌套 Break、continue、goto语句 exit()函数 循环结构类型的选择及转换 循环结构程序设计举例 本章小结,学习目标,理解循环结构的含义;掌握C语言三种循环结构的特点;掌握while、do-while、for、goto、break、continue语句的使用方法;掌握不同循环结构的选择及其转换方法;掌握混合控制结构程序设计的方法。,学习内容,6.1 循环结构的程序设计,1.while语句,一般形式:,while(表达式)循环体语句;,执行流程:,其中:while后面的括号()不能省。while后面的表达式可以是任意类型的表达式,但一般是条件表达式或逻辑表达式。表达式的值是是循环的控制条件。语句部分称为循环体,当需要执行多条语句时,应使用复合语句。,特点:先判断表达式,再执行循环体,【例】用while语句求1100的累计和。,#include void main()int i=1,sum=0;while(i=100)sum+=i;i+;printf(sum=%dn,sum);,循环初值,循环终值,循环条件,循环体,循环变量增值,运行结果:sum=5050,【例】显示110的平方,#include void main()int i=1;while(i=10)printf(%d*%d=%dn,i,i,i*i);i+;,运行结果:1*1=12*2=43*3=94*4=165*5=256*6=367*7=498*8=649*9=8110*10=100,(1)如果while后的表达式的值一开始就为假,循环体将一次也不执行。(2)循环体中的语句可为任意类型的C语句。(3)遇到下列情况,退出while循环:表达式为假(为0)。循环体内遇到break、return或goto语句(break和goto语句将在随后介绍)。,while语句注意事项:,int a=0,b=0;while(a 0)/a 0为假,b+不可能执行 b+;,int num=0;/字符计数while(1)if(getche()=n)/如果输入的字符是回车符,则返回 return;num+;,(4)在执行while语句之前,循环控制变量必须初始化,否则执行的结果将是不可预知的。(5)要在while语句的某处(表达式或循环体内)改变循环控制变量,否则极易构成死循环。(6)允许while语句的循环体又是while语句,从而形成双重循环。,while语句注意事项:,例:计算10!#include void main()int i;/i应赋初始值10 long s=1;while(i=1)s*=i-;printf(10!=%ldn,s);,i=1;while(i 100)/死循环,因为i的值没变化,永远小于100 sum+=i;printf(sum=%dn,sum);,i=1;while(i=9)j=1;while(j=9)printf(%d*%d=%dn,i,j,i*j);j+;i+;,【例】求两个正整数的最大公因子。我们采用Euclid(欧几里德)算法来求最大公因子,其算法是:(1)输入两个正整数m和n。(2)用m除以n,余数为r,如果r等于0,则n是最大公因子,算法结束,否则(3)。(3)把n赋给m,把r赋给n,转(2)。,#include void main()int m,n,r;printf(Please input two positive integer:);scanf(%d%d,运行结果:Please input two positive integer:24 56Their greatest common divisor is 8,2.do_while语句,一般形式:,do 循环体语句;while(表达式);,执行流程:,其中:while后面的括号()不能省。while最后面的分号;不能省。while后面的表达式可以是任意类型的表达式,但一般是条件表达式或逻辑表达式。表达式的值是是循环的控制条件。语句部分称为循环体,当需要执行多条语句时,应使用复合语句。,特点:先执行循环体,再判断表达式,【例】用do_while语句求1100的累计和。,#include void main()int i=1,sum=0;do sum+=i;i+;while(i=100);printf(sum=%dn,sum);,运行结果:sum=5050,do_while语句注意事项:,int a=0,b=0;do b+;while(a 0);,(1)如果do-while后的表达式的值一开始就为假,循环体还是要执行一次。(2)在if语句、while语句中,表达式后面都不能加分号,而在do-while语句的表达式后面则必须加分号,否则将产生语法错误。(3)循环体中的语句可为任意类型的C语句。(4)和while语句一样,在使用do-while语句时,不要忘记初始化循环控制变量,否则执行的结果将是不可预知的。(5)要在do-while语句的某处(表达式或循环体内)改变循环控制变量的值,否则极易构成死循环。(6)do-while语句也可以组成多重循环,而且也可以和while语句相互嵌套。,3.for语句,一般形式:,for(表达式1;表达式2;表达式3)循环体语句;,执行流程:,其中:for后面的括号()不能省。表达式1:一般为赋值表达式,给控制变量赋初值。表达式2:关系表达式或逻辑表达式,循环控制条件。表达式3:一般为赋值表达式,给控制变量增量或减量。表达式之间用分号分隔。语句部分称为循环体,当需要执行多条语句时,应使用复合语句。,for语句很好地体现了正确表达循环结构应注意的三个问题:控制变量的初始化。循环的条件。循环控制变量的更新。,【例】用for语句求1100的累计和。,#include void main()int i,sum=0;for(i=1;i=100;i+)sum+=i;printf(sum=%dn,sum);,运行结果:sum=5050,for语句注意事项:,例:计算1*2+3*4+5*6+99*100。int i,j;long sum=0;for(i=1,j=2;i=99;i=i+2,j=j+2)sum+=i*j;printf(sum=%ldn,sum);,(1)表达式1、表达式2、和表达式3可以是任何类型的表达式。比方说,这三个表达式都可以是逗号表达式,即每个表达式都可由多个表达式组成。,逗号表达式,逗号表达式,#include void main()int i,sum=0;i=1;for(;i=100;i+)sum+=i;printf(sum=%dn,sum);,#include void main()int i,sum=0;i=1;for(;i=100;)sum+=i+;printf(sum=%dn,sum);,for语句注意事项:,省掉表达式1,3,省掉表达式1,(2)表达式1、表达式2、和表达式3都是任选项,可以省掉其中的一个、两个或全部,但其用于间隔的分号是一个也不能省的。,#include void main()int i,sum=0;i=1;for(;)if(i 100)break;sum+=i+;printf(sum=%dn,sum);,省掉表达式1,2,3,for语句注意事项:,for(a=1;a+)printf(,(3)表达式2如果为空则相当于表达式2的值是真。,死循环!,(4)循环体中的语句可为任意类型的C语句。(5)for语句也可以组成多重循环,而且也可以和while语句和do-while语句相互嵌套。(6)循环体可以是空语句。,例:计算用户输入的字符数(当输入是回车符时统计结束)。#include void main()int n=0;printf(input a string:n);for(;getchar()!=n;n+);printf(%d,n);,表示循环体为空语句,并非表示for语句结束,三种循环可互相嵌套,层数不限 外层循环可包含两个以上内循环,但不能相互交叉 嵌套循环的执行流程,(1)while()while().,(2)do do while();.while();,(3)while()do while();.,嵌套循环的跳转禁止:从外层跳入内层 跳入同层的另一循环 向上跳转,4.循环嵌套,【例】循环嵌套,输出九九表,#include void main()int i,j;for(i=1;i 10;i+)printf(%4d,i);printf(n-n);for(i=1;i 10;i+)for(j=1;j 10;j+)printf(j=9)?%4dn:%4d,i*j);,for(i=1;i10;i+)for(j=1;j10;j+)printf(j=9)?%4dn:%4d,i*j);,5.break与continue语句,break语句功能:在循环语句和switch语句中,终止并跳出循环体或开关体说明:(1)break不能用于循环语句和switch语句之外的任何其它语句之中。(2)break只能终止并跳出最近一层的结构。,while(表达式1)if(表达式2)break;语句,do if(表达式2)break;while(表达式1);语句,for(;表达式1;)if(表达式2)break;语句,【例】将用户输入的小写字母转换成大写字母,直到输入非小写字母字符。,#include void main()char c;while(1)c=getchar();/读取一个字符 if(c=a/循环退出,运行结果:howareyouHOWAREYOU,方法:通过设置一标志变量tag,然后在每层循环后加上一条语句:if(tag)break;其值为1表示跳出循环体,为0则不跳出。,for()while()if()break;while循环后的第一条语句,int tag=0;for()while()if()tag=1;break;if(tag)break;for循环后的第一条语句,多重循环中,break的使用,问:在嵌套循环的情况下,如何让break语句跳出最外层的的循环体?,continue语句功能:结束本次循环,跳过循环体中尚未执行的语句,进行下一次是否执行循环体的判断。说明:(1)仅用于循环语句中。(2)在嵌套循环的情况下,continue语句只对包含它的最内层的循环体语句起作用。,for()while()if()continue;while循环后的第一条语句,【例】求输入的十个整数中正数的个数及其平均值。,#include void main()int i,a,num=0;float sum=0;for(i=0;i 10;i+)scanf(%d,运行结果:8 plus integers sum:45average value:5.63,假设输入的10个整数为:2 3 4 5 6 7 8 9 10,5.goto语句,一般形式:,goto 语句标号;语句标号:,语句标号:goto 语句标号;,或,说明:,语句标号是按标识符规定书写的符号,放在某一语句行的前面,标号后加冒号(:)。语句标号起标识语句的作用,与goto 语句配合使用。,作用:,goto语句的作用是在不需要任何条件的情况下直接使程序跳转到该语句标号所标识的语句去执行。,goto语句的应用:,例:求1100的累计和#include void main()int i=1,sum=0;loop:sum+=i+;if(i=100)/如果i小于或等于100 goto loop;/转到标号为loop的语句去执行 printf(sum=%dn,sum);,(1)goto语句可与条件语句配合使用来实现条件转移,构成循环。(2)在嵌套循环的情况下,利用goto语句可以直接从最内层的循环体跳出最外层的循环体。,int tag=0;for()while()if()goto stop;stop:for循环后的第一条语句,注意:在结构化程序设计中一般不主张使用goto语句,以免造成程序流程的混乱,使理解和调试程序都产生困难。,6.exit()函数,功能:,说明:,参数status为int型,status的值传给调用进程(一般为操作系统)。按照惯例,当status的值为0或为宏常量EXIT_SUCCESS时,表示程序正常退出;当status的值为非0或为宏常量EXIT_FAILURE时,表示程序出现某种错误后退出。,终止整个程序的执行,强制返回操作系统。,调用形式:,void exit(int status);头文件,程序设计分析:由数学知识可知,求三角形面积的公式是:其中,a、b、c是三角形的三个边长,s=(a+b+c)/2。因此,程序中应该有三个float型变量用来存放a、b、c的值,为了方便起见,还应有一个变量存放s,最后有必要设置一个变量来存放三角形的面积值。公式中存在求平方根的操作,这要用到C语言数学库函数sqrt。sqrt函数带有一个参数,它的功能是返回参数的平方根。程序在开始接受用户输入的三角形的三个边长后,首先要对这三边作合法性检查,如三边中有某一边长度小于或等于0,则终止程序的执行,同样如果s*(s-a)*(s-b)*(s-c)为负,也要终止程序的执行。,【例】输入三角形的边长,求三角形面积。,#include#include#include void main()float a,b,c;float s,area;printf(input the length of three edges of triangle:);scanf(%f%f%f,s=(a+b+c)/2;s=s*(s-a)*(s-b)*(s-c);if(s 0)printf(the length of three edges of triangle is error!n);exit(-1);area=(float)sqrt(s);printf(area=%.2fn,area);,运行结果:input the length of three edges of triangle:3 4 5area=6.00input the length of three edges of triangle:3-4 5the length of three edges of triangle is error!,6.2 循环结构类型的选择及转换,1.循环结构类型的选择原则,如果循环次数在执行循环体之前就已确定,一般用for循环;如果循环次数是由循环体的执行情况确定的,一般用while循环或者do-while循环。当循环体至少执行一次时,用do-while循环,反之,如果循环体可能一次也不执行,选用while循环。,2.循环结构类型之间的相互转换,尽管上面对于循环结构的选择给出了原则性指导意见,但是我们应注意到其实这三种循环结构彼此之间可以相互转换,象前面我们分别用while循环、do-while循环、for循环来求1100的累计和的例子就说明了这一点。,【例】求1100之间的所有素数,问题分析:素数是指除了能被1和它本身整除外,不能被其它任何整数整除的数。例如,17就是一个素数,除了1和17之外,它不能被216之间的任何整数整除。根据素数的这个定义,可得到判断素数的方法:把m作为被除数,把i=2(m-1)依次作为除数,判断被除数m与除数i相除的结果,若都除不尽,即余数都不为0,则说明m是素数,反之,只要有一次能除尽(余数为0),则说明m存在一个1和它本身以外的另一个因子,它不是素数。事实上,根本用不着除那么多次,用数学的方法可以证明:只需用2 之间(取整数)数去除m,即可得到正确的判定结果。,这一思路的算法如下:从键盘输入一正整数m。计算k=i从2变化到k,依次检查m%i是否为0。若m%i为0,则判定m不是素数,并终止对其余i值的检验;否则,令i=i+1;并继续对其余i值进行检验,直到全部检验完毕为止,这时判定m是素数。,6.3 循环结构程序设计举例,【例1】验证哥德巴赫猜想:任一充分大的偶数,可以用两个素数之和表示。例如:4=2+2,6=3+3,98=19+79,这一思路的算法如下:读入大于3的偶数n。p=1 do p=p+1;q=n-p;p是素数吗?q是素数吗?while p、q有一个不是素数。输出n=p+q。,问题分析:读入一个偶数n,将它分成p和q,使n=p+q。怎样分呢?可以令p从2开始,每次加1,而令q=n-p,如果p、q均为素数,则正为所求,否则令p=p+1再试。,flagp=1;for(j=2;j=(int)sqrt(p);j+)if(p除以j的余数=0)flagp=0;break;,flagq=1;for(j=2;j=(int)sqrt(q);j+)if(q除以j的余数=0)flagq=0;break;,设置两个标志量flagp和flagq,0是素数,1不是素数 while(flagp*flagq=0);,#include#include#include void main()int i,n,p,q,flagp,flagq;printf(please input n:);scanf(%d,/程序结束,p=1;do p+;q=n-p;flagp=1;for(i=2;i=(int)sqrt(p);i+)if(p%i=0)flagp=0;break;flagq=1;for(i=2;i=(int)sqrt(q);i+)if(q%i=0)flagq=0;break;while(flagp*flagq=0);printf(%d=%d+%dn,n,p,q);,判断p是否为素数,判断q是否为素数,运行结果:please input n:9898=19+79please input n:9input data error!,【例】利用下面的公式求的近似值,要求累加到最后一项小于10-6为止。,问题分析:这是一个累加求和的问题,但这里的循环次数是预先未知的,而且累加项以正负交替的规律出现,如何解决这类问题呢?在本例中,累加项的构成规律可用寻找累加项通式的方法得到,具体表示为t=s/n;即累加项由分子和分母两部分组成,分子s按+1,-1,+1,-1,交替变化,可用赋值语句s=-s;实现,s的初始值取为1,分母n按1,3,5,7,变化,用n=n+2;语句实现即可,n的初始值取为1.0。,#include#include void main()int s=1;float n=1.0,t=1,pi=0;while(fabs(t)=1e-6)pi+=t;n+=2;s=-s;t=s/n;pi*=4;printf(pi=%.6fn,pi);,运行结果:pi=3.141594,【例】打印大小可变的菱形图案(下面菱形的大小是7)。,问题分析:菱形的大小size其实就是中间行中*号的个数,也是整个菱形的行数,其值必须是奇数。问题的关键之一是如何确定每行中*号的个数。经过分析得知:当行数i(假设最上面的一行为第1行)(size+1)/2时,该行上的*号个数为n=2*i-1,否则n=2*(size-i+1)-1。问题的关键之二是如何确定每行显示的第一个*号的位置,也就是显示第一个*号之前应显示多少个空格。经过分析得知:每行应显示的空格数为m=(size-n)/2个。,#include#include void main()int i,j,k,m,n,size;printf(input size:);/输入大小提示 scanf(“%d”,/程序结束,for(i=1;i=size;i+)/控制行数 n=(i=(size+1)/2)?i:size-i+1;/每行中*号的个数 n=2*n-1;m=(size-n)/2+15;/每行打印*之前应打印的空格数 for(k=1;k=m;k+)/打印每行前面的空格 printf();for(j=1;j=n;j+)/打印每行的*printf(*);printf(n);/打印一行后,回车换行,【例】计算用户输入的两正整数之间的所有整数中0,1,2,9数码的个数。例如,101104之间总共包含四个整数101,102,103,104,其中0的个数为4,1的个数为5,2、3、4的个数都为1,其余数码没出现都为0。,问题分析:问题的关键是要计算某整数中包含的各个数码的个数,必须对该整数进行分解,求得所包含的各个数码,其方法可以通过每次除以10取余数得到,然后再对商进行同样的处理,直到商为0时为止。对所得到的数码进行计数,可采用switch语句来实现。,#include#include void main()int num1,num2;int n,s,r;int count0=0,count1=0,count2=0,count3=0,count4=0;int count5=0,count6=0,count7=0,count8=0,count9=0;printf(input two integer:);scanf(%d%d,for(n=num1;n=num2;n+)s=n;do r=s%10;switch(r)case 0:count0+;break;case 1:count1+;break;case 2:count2+;break;case 3:count3+;break;case 4:count4+;break;case 5:count5+;break;case 6:count6+;break;case 7:count7+;break;case 8:count8+;break;case 9:count9+;break;s=s/10;while(s!=0);/for,printf(0-%-4d 1-%-4d 2-%-4d 3-%-4dn,count0,count1,count2,count3);printf(4-%-4d 5-%-4d 6-%-4d 7-%-4dn,count4,count5,count6,count7);printf(8-%-4d 9-%-4dn,count8,count9);,运行结果:input two integer:1500 30000 403 1 900 2 1400 3 4014 400 5 500 6 500 7 5008 500 9 500,本章小结,本章主要讨论了循环结构程序设计的有关方法,重点介绍了与C语言三种循环控制结构有关的while语句、do-while语句及for语句。本章所涉及到的主要关键字有:while、do、for、goto、break、continue。语言提供了三种循环语句。for语句主要适用于循环次数确定的循环结构。循环次数及控制条件要在循环过程中才能确定的循环可用 while或do-while语句。三种循环语句可以相互嵌套组成多重循环,循环之间可以并列但不能交叉。三种循环结构可以相互转换。可用转移语句把流程转出循环体外,但不能从外面转向循环体内。在循环程序中应避免出现死循环,即应保证循环控制变量的值在运行过程中可以得到修改,并使循环条件逐步变为假,从而结束循环。break、continue和goto语句都可用于流程控制。其中,break语句用于退出switch或一层循环结构,continue语句用于结束本次循环,继续执行下一次循环,goto语句无条件转移到标号所标识的语句处去执行。当程序需要退出多重循环时,用goto语句比用break语句更直接方便;当需要结束程序运行时,可以调用exit()函数来实现。,习题:P167P173 1、2、3、4(1、3、4、6、8、12),