1、第4章 程序的控制结构,2,内容提要,算法的描述方法 基本控制结构 基本控制语句 常用算法,如累加、累乘、统计、递推、迭代、穷举等 程序的基本版式 结构化程序设计的基本思想,3,算法的概念,数据结构+算法=程序 算法:为解决一个具体问题而采取的确定的有限的操作步骤,这里仅指计算机能执行的算法 算法特性: 有穷性 确定性 有效性 没有输入或有多个输入 有一个或多个输出,4,算法的分类,数值运算算法: 解决的是求数值解的问题,例如用辗转相除法求两个数的最大公约数等 非数值运算算法: 主要用于解决需要用分析推理、逻辑推理才能解决的问题,例如人工智能中的许多问题,查找、分类等问题,5,算法的表示方法,
2、自然语言表示 传统的流程图表示 N-S结构化流程图表示 伪代码表示,6,C程序结构,7,构成程序的三种基本结构,顺序结构 选择结构 循环结构 已经证明,任何程序均可只用这三种结构综合描述 只用这三种结构编制的程序,叫结构化程序 程序必须符合结构化规则,8,结构化程序设计的核心思想,采用顺序、选择和循环三种基本结构作为程序设计的基本单元 只有一个入口; 只有一个出口; 无死语句,即不存在永远都执行不到的语句; 无死循环,即不存在永远都执行不完的循环。 采用“自顶向下、逐步求精”和模块化的方法进行结构化程序设计,9,B,A,NS图,传统流程图,顺序结构,B,A,10,#include main (
3、 ) float a,b,c,s,area ;scanf(“%f,%f,%f“, ,求平方根函数,例4.1 输入三角形的三边长,求三角形面积(假设输入三边长能构成三角形)。 设a,b,c为三角形边长,面积 area= sqrt(s*(s-a)*(s-b)*(s-c),其中s=(a+b+c)/2.,11,#include #include main( )float a,b,c,disc,x1,x2,p,q ;scanf(“%f,%f,%f“,例 4.2 求二次方程 ax2+bx+c=0的根。设 b2-4ac0, a不等于零。,12,B,N,如果 成绩60 那么通知补考 否则告知你考试成绩,A,Y
4、,条 件P,分支结构(选择结构),13,if 语句用来判定给定的条件是否满足,根据判定的结果来决定执行何种操作。 if 语句的三种形式1. if (表达式) 语句;,例如: if (xy) printf(“%d“, x);,if 语句,注意:如何表示score在90100之间?,14,2. if (表达式) 语句 1 else 语句 2,例如: if (xy)printf(“%d“,x);elseprintf(“%d“,y);,15,3. if (表达式1) 语句 1else if (表达式2) 语句 2else if (表达式3) 语句 3.else if (表达式n) 语句 nelse 语
5、句 n+1(else部分可以没有),if (x1) y=1; else if(x0) y=0.5; else if(x-1) y=-0.5; else y=-1;,只执行一个(组)语句,16,if 语句中的“表达式”可以是任何数值类型(整型、实型、字符型等),只要“表达式”的值 不等于0, 就执行后面的“语句”。例如:if(a=b ”,注意:,17,例 考虑下面程序的输出结果: #include main() int x,y;scanf(“%d,%d”, ,Compile Error!,18,例 4.3 输入两个实数,按从小到大的次序输出 。,main()float a,b,t;printf(
6、“Input a and b:“);scanf(“%f,%f“,注意如何交换两个数, 是否可以写为: a=b; b=a;,19,if语句嵌套,20,缺省 时,else总是和它上面离它最近的未配对的if配对,和缩写层次没关系。,if else 配对原则:,21,例: if (a=b)if(b=c)printf(“a=b=c”);elseprintf(“a!=b”);,修改: if (a=b) if(b=c)printf(“a=b=c”);elseprintf(“a!=b”);,实现if else 正确配对方法:加 ,22,写出算法:输入x 若x0 y=1 输出 y,或: 输入x 若x0 y=1
7、输出 y,23,main() int x,y;scanf(“%d“, ,main() int x,y;scanf(“%d“, ,main() int x,y;scanf(“%d“, ,main() int x,y;scanf(“%d“, ,1,3,4,2,24,例 4.4 猜数并提示所猜的数比magic 数大还是小。 #include main ( )int magic=rand()%10+5 ;int guess ;printf(“Please input the guess number :“) ;scanf(“%d“,25,猜数游戏用到的库函数,随机函数rand() #include R
8、AND_MAX在stdlib.h中定义,不大于双字节整数的最大值32767 产生0,RAND_MAX 之间的随机数 magic = rand(); 产生0,b-1 之间的随机数 magic = rand()%b; 产生a,a+b-1 之间的随机数 magic = rand()%b + a;,26,猜数游戏用到的库函数,函数srand 为函数rand()设置随机数种子来实现对函数rand所产生的伪随机数的 “随机化” 通过键入随机数种子,产生0,100之间的随机数 scanf(“%u“, ,27,猜数游戏用到的库函数,使用计算机读取其时钟值并把该值自动设置为随机数种子,产生0,100之间的随机数
9、 函数time()返回以秒计算的当前时间值,该值被转换为无符号整数并用作随机数发生器的种子 #include srand(time(NULL); magic = rand() % 100 + 1;,28,#include main( ) char c ;printf(“Please input a character:“) ;c=getchar( ) ;if(c=0 ,例 4.5 从键盘输入字符,将字符分类:控制字符 : ASCII 码小于32 数字字符 : 09 大写字母字符 : AZ 小写字母字符 : az 其它,29,例4.6 求 ax2+bx+c=0 方程的根。有以下几种可能: a=0
10、, 不是二次方程 b*b-4*a*c=0, 有两个相等实根 b*b-4*a*c0, 有两个不等实根 b*b-4*a*c0, 有两个共轭复根,30,#include main( ) float a, b, c, disc, x1, x2, realpart, imagpart ;scanf(“%f,%f,%f“, ,31,4.3.4 switch 语句,switch 语句是多分支选择语句。if 语句只有两个分支,当遇到多分支选择时,可以用嵌套 if 语句来处理,但是由于需要嵌套的 if 语句层次多,因此程序的可读性降低。C语言中的 switch 语句可直接处理多分支选择,它的一般形式是:,swi
11、tch (表达式) case 常量表达式1 : 语句 1case 常量表达式2 : 语句 2case 常量表达式n : 语句 ndefault : 语句 n+1,例:根据考试成绩的等级打印出百分制分数段。 switch(grade) case A : printf(“85100n“) ;case B : printf(“7084n“) ; case C : printf(“6069n“) ; case D : printf(“60n“) ; default : printf(“errorn“) ;,注意:不允许含有变量或函数调用,且不能表示数值范围。,32,switch 后面括号内的“表达式”
12、可以是整型或字符型表达式,或枚举类型数据,不能为实型或字符串。 当“表达式”的值与某个 case 后面的常量表达式的值相等时,就执行这个 case 后面的语句,如果 所有的 case 中的常量表达式的值都没有与“表达式”的值相匹配,就执行 default (缺省)后面的语句。 每个 case 的常量表达式的值必须互不相同, 否则会出现相互矛盾的现象(对表达式的同一个值,有两种或多种执行方案)。 各个 case 和 default 的出现次序不影响执行的结果。例如,在上面的例子中,可以先出现“case D : ”,然后是 “ case A: ”。,注意 :,33,执行完一个case 后面的语句后
13、,流程控制转移到下一个case 继续执行。“case 常量表达式”只是起标号作用,并不是在该处进行条件判断。在执行switch 语句时,根据switch 后面表达式的值找到匹配的入口标号,然后从此标号处开始执行下去,不再执行判断。例如,在上面的例子中,若grade的值等于 C,则将连续输出:606960error,因此,应该在执行完一个 case 分支后, 使流程跳出 switch 结构,即终止 switch 语句的执行。可以在 case 后面的 语句之后再用一个 break 语句来使流程跳出 switch 结构。最后一个分支可以不加 break语句,因为后面switch 结构已经结束了。,3
14、4,由于从对应的 case 开始,程序会自动执行后面的语句,直至结束或遇到 break语句后 跳出 switch 结构,因此每个 case 后面的语句不需要用复合语句。当然加上花括弧也可以。,switch (表达式) case 常量表达式1: 语句1; case 常量表达式2: 语句2; case 常量表达式n: 语句n; default : 语句n+1; ,break;,break;,break;,35,例4.7:要求按考试成绩的等级输出百分制分数段。main( ) char grade ;scanf(“%c“, ,如果grade值为B,则输出“7084“。 如没有break 语句,则将连续
15、输出: 7084 6069 60 error,36,6. 多个 case 可以共用一组语句。 如:, case A : case B : case C : printf(“60“); break ; ,当 switch 后面的表达式的值等于A 或B或C时,都执行 case C之后的 “printf(“60“); break; ” 语句。,37,例4.8,编程设计一个简单的计算器程序,要求根据用户从键盘输入的表达式:操作数1 运算符op 操作数2然后,计算表达式的值,指定的运算符为加(+)、减(-)、乘(*)、除(/),38,#include void main() int data1, dat
16、a2;char op;printf(“please input the expression:“);scanf(“%d%c%d“, ,39,4.4 循环控制,循环结构是结构化程序设计的基本结构之一。,40,4.4.1 概 述,C语言中的循环结构可以用以下语句实现:1.用 while 语句2.用 do-while 语句3.用 for 语句,41,例4.9: x=y=1 ;while (y10)+y ;x+=y ;printf(“x=%d, y=%dn“, x, y);,1. while 语句,while 语句 用来实现“ 当型循环” 结构。一般形式: while (表达式) /()是必须有的,且
17、)与循环体间无任何东西语句,“语句” 部分就是循环体, while循环 先判断表达式的值,后执行语句。 当“表达式”为 非0 值时执行该语句,直到“表达式”为 0 时跳出循环。,注意: 如果语句部分包含一个以上的语句,应该用复合语句 “ ” 的形式。 在循环体中应有使循环趋于结束的语句。,x=11, y=10,x=55, y=10,42,#include main() int i,sum=0;i=1;while(i=100) sum=sum+i;i+;printf(“%d“,sum); ,例 4.10 用 while 语句构成循环,求 1+2+3+.+100。,循环体中有两个语句,要用 括起来
18、。 其中 i+ 是改变条件表达式值的语句。,43,2. do-while 语句,do-while 语句用来实现 “直到型” 循环结构。一般形式: do 循环体语句while (表达式) ; /分号在这里是必须的,执行过程:先执行一次指定的 “循环体语句”,然后判别 “表达式”,当 “表达式”的值为 非0 时,返回重新执行 “循环体语句”,如此反复,直到表达式的值等于0为止,此时循环结束。即do-while 语句至少执行一次循环体。 注意: 当“语句”部分最好用使用复合语句“ ”的形式,否则容易引起误会; 在循环体中应有使循环趋于结束的语句。,44,例4.11 用 do-while 语句构成循环
19、,求 1+2+3+.+100,main() int i, sum=0;i=1;do sum=sum+i;i+; while(i=100) ;printf(“%dn“, sum) ; ,45,do-while 语句的while 语句后要加分号 “ ;”。 while 语句可能一次也不执行循环体, 但do-while 语句至少执行一次循环体。对于同一个问题, 既可以用 while 语句 , 也可以用 do-while 语句处理。do-while 结构可以转换成while 结构, 即do-while 结构由一个语句和一个while 结构构成。,说明:,46,在一般情况下,用while语句和用do-w
20、hile处理同一问题时,若二者的循环体部分是一样的, 它们的结果也一样。但是如果while 后面的表达式一 开始就为假(0),两种循环的结果是不同的。亦即当while 后面的表达式第一次的值为真(非0)时,两种循环得到的结果相同。否则结果不同。,例 while和do-while循环的比较。,47,(2) main( ) int sun=0, i;scanf(“%d“,(1) main( ) int sum=0, i ; scanf(“%d”, ,运行情况如下: 1 ,再运行一次: 12 ,(1) sum=0 (2) sum=12,(1) sum=55 (2) sum=55,例 while和do
21、-while循环的比较。,48,一般形式: for ( 表达式1; 表达式2; 表达式3 )语句,执行过程: 1. 求解表达式1;2. 求解表达式2: 如果值为真(非0), 则执行“语句”部分;如果值为假( 0 ),则结束循环;3. 当表达式2为真时, 在执行了“语句”部分后, 求解表达式3;4. 转到第2步继续执行。 说明:当“语句”部分包含一个以上的语句时,应该用复合语句 “ ” 的形式。,3 for 语句,for 语句既可用于循环次数已经确定的情况,也可用于循环次数不确定而只给出循环结束条件的情况,它完全可以代替while语句。,49,for 语句最常用的形式:for ( 循环变量赋初值
22、 ; 循环结束条件 ; 循环变量增值 ) 语句,main() int i, sum=0;for (i=1;i=100;i+)sum=sum+i ;printf(“%d“,sum) ; ,例4.12:用 for 语句构成循环, 求1+2+3+.+100。,50,for 循环语句也可以写为while 语句形式:,51,如果 “表达式2” 省略,即不判断循环条件,则认为 表达式 2 始终为真,此时循环无法终止(死循环)。for( i=1 ; ; i+) sum+=i ;,如果 “表达式3” 省略,则程序中必须有保证循环能正常结束的措施。,说明: 若循环变量在 for 语句之前已经赋初值,则for 语
23、句的一般形式中的“表达式1”可以省略,但是“;” 不能省略。例如: i=1 ;for( ; i=100 ; i+) sum+=i ;,for( i=1 ; i=100 ; ) sum+=i ;i+ ; ,52,三个表达式都省略,如 for( ; ; ) 语句相当于 while(1) 语句即不设初值,不判断条件(认为表达式2为真),循环变量不增值,无终止地执行循环体 (死循环) 。,可以省略表达式1 和 表达式3,只有表达式2,即只给循环条件for( ; i=100 ; ) while (i=100) sum=sum+i ; 相当于 sum=sum+i;i+ i+ ,在这种情况下,for语句完全
24、等同于while语句。可见,for 语句比while 语句功能强,除了可以给出循环条件外,还可以赋初值,使循环变量自动增值等。,53,“表达式1” 既可以是设置循环变量初值的赋值表达式,也可以是与循环变量无关的其它表达式。如i=1 ;for(sum=0 ; i=100 ; i+) sum=sum+i ;,“表达式1” 和 “表达式3” 可以是一个简单的表达式,也可以是逗号表达式。 例如: for (sum=0, i=1 ; i=100 ; i+) sum=sum+i;for (i=1 , j=100 ; i=j ; i+, j- -) k+=i+j;,在逗号表达式内按自左至右顺序求解,整个逗号
25、表达式的值为其中最右边的表达式的值。如for (sum=0, i=1 ; i=100 ; i+,i+) sum=sum+i; 相当于 for (sum=0, i=1 ; i=100 ; i+=2) sum=sum+i;,54,“表达式2”一般是关系表达式或逻辑表达式,但也可以是数值表达式或字符表达式, 只要其值非0,就执行循环体。分析: for( i=0; (c=getchar( ) )!=n; i+=c ) ;及 for( ; (c=getchar( ) )!=n ; ) putchar(c) ;,由于 for 语句功能很强,尽量按 for 语句的规范来写,也尽量不要把与循环控制无关的内容放
26、到 for 语句中。,55,例. 分别用while、do-while、for 语句构成的循环求n!。,56,几种循环的比较,1. while 和 do-while 循环,在while 后面指定循环条件,而使循环趋于结束的语句包含在循环体中。for 循环可以在“表达式3”中包含使循环趋于结束的操作,甚至可以将循环体中的操作全部放到“表达式3”中。因此,for 语句的功能更强,凡是用while 循环能完成的,用for 循环都能实现。 2. 用while 和 do-while循环时,循环变量初始化应在 while 和 do-while之前,for 循环可以在“表达式1” 中实现循环变量的初始化。 3
27、. while 循环先判断,后执行; do-while 循环先执行,后判断;for 循环先判断,后执行。 4. 对 while循环、do-while循环、for 循环,可以用 break 语句跳出循环,还可以用 continue 语句结束本次循环。,57,选择三种循环的一般原则,如果循环次数已知,用for 如果循环次数未知,用while 如果循环体至少要执行一次,用do-while 这只是“一般”原则,不是“原则”,58,注意,在for和while语句之后一般没有分号 有分号表示循环体就是分号之前的内容(空循环体) while (i 100); i+; for (i = 0; i 100; i
28、+); printf(“%d“, i); for通常有一个循环变量控制循环的次数,尽量不要在循环体内改变这个变量,59,死循环,永远不会退出的循环为死循环 for (;) while (1) do while (1) 一般情况下,要极力避免死循环 绝大多数程序不需要死循环。如果出现,往往都是bug 时间过长的循环会造成“假死”效果,也要考虑解决,60,4.5.2 循环的嵌套,三种循环( while 循环、do-while 循环和 for 循环)可以互相嵌套。 (1) while( ) do for( ; ;) : : while( ) do for( ; ;) : : : : while( )
29、 ; while( ) ; (2) while( ) do( ) for( ; ;) : : :do for(;) while( ) while( ); . : while( ) ; : ,一个循环体内又包含另一个完整的循环结构时,称为循环的嵌套。内嵌的循环中还可以嵌套循环,即循环嵌套可以多于一层,这就是多层循环嵌套。,61,例4.13:屏幕输出9*9乘法口诀表。分析:分行与列考虑,共9行9列,i控制行,j控制列。一般二维表 格可以用双重循环处理。(改成三角形怎么改?) #include main() int i,j,result; printf(“n“); for (i=1;i10;i+)
30、for(j=1;j10;j+) result=i*j;printf(“%d*%d=%-3d“,i,j,result); /*-3d表示左对齐,占3位*/ printf(“n“);/*每一行后换行*/ ,62,使用嵌套的循环体时,应注意以下问题,在嵌套的各层循环体中,使用复合语句(即用一对大花括号将循环体语句括起来)保证逻辑上的正确性 内层和外层循环控制变量不应同名,以免造成混乱 嵌套的循环最好采用右缩进格式书写,以保证层次的清晰性 循环嵌套不能交叉,即在一个循环体内必须完整的包含着另一个循环,63,合法的嵌套循环,64,4.5.2 break语句和continue,1.break 语句brea
31、k 语句除了可以用来跳出 switch 结构之外,还可以用来从循环体内 跳出循环,即提前结束循环,接着执行循环下面的语句。如,当 r=6时,area大于100,这时执行break语句,提前结束循环,即不再继续执行其余的几次循环。,if(area100) break;,for(r=1;r=10;r+) area=pi*r*r;printf(“%fn“, area); ,r=1, area=3.14 r=2, area=12.56 r=3, area=28.26 r=4, area=50.24 r=5, area=78.5 r=6, area=113.04,65,2. continue 语句:只能
32、用于循环语句语句的一般形式: continue ;作用: 结束本次循环, 即跳过循环体中的 continue 之后的其它语句,而转到进行下一次是否执行循环的判断。,break 语句的一般形式: break ;,注意: break 语句只能用于循环语句和 switch 语句,不能用于其它语句。,break语句和continue语句的区别: continue 语句只结束本次循环,然后进行是否执行下一次循环的判断,而不是终止整个循环的执行。 break语句结束整个循环过程,不再进行条件判断。,66,67,只输出100,101。因为102%3= =0,则break 跳出循环。,例4.14 输出 100
33、-200 之间的不能被 3 整除的数。,main( ) int n;for (n=100 ; n=200 ; n+) if (n%3=0)continue; printf(“%dn“,n); ,当n 能被3 整除时,执行continue语句,结束本次循环(即跳过printf函数语句), 只有n不能被3整除时才执行printf函数。,68,注意:在嵌套情况下,break和continue只对包含他们的最内层循环起作用,for ()while()if () break;while循环后的第一条语句 ,for ()while()if () continue;while循环后的第一条语句 ,69,#i
34、nclude main( ) int s;float n, t, pi;t=1; n=1;s=1; pi=0;while ( fabs(t)=1.0e-6 ) pi=pi+t;n=n+2;s= -s;t=s/n; /*若n定义为int ?*/pi=pi*4;printf(“%fn“,pi); ,变量说明: pi 级数和 t 一般项 n 分母 s 符号,例 4.15 用公式求的近似值, 直到最后一项的绝对值 10-6 。,70,#include main() int m,i,k;scanf(“%d“, ,例4.16 判断一个数是否为素数 ( 只能被 1 和 自身 整除的数) 对于一个数 m ,
35、当 m 不能被 2 之中的任一整数整除时, m 是素数。,注意: 循环正常结束时 i 的值是 k+1。,71,例4.17 求100200间的全部素数。,#include main( ) int m,k,i,n=0;for(m=101; m=k+1) printf(“%-8d“,m) ;n=n+1;if(n%10=0) printf(“n“);printf(“n“); ,72,例4.18,a+aa+aaa+aaaa+aaaaa+a是一个数字,例a=2,2+22+222+2222+,73,例4.19,使用循环产生如下图案 (1)$ (2) $ (3)$ $ $ $ $ $ $ $ $ $ $,74
36、,例4.20,使用循环产生如下图案 F FE FED FEDC FEDCB FEDCBA,75,例4.21,使用循环产生如下图案(用户输入一个字母E时)AABABCABCDABCDE ABCDEF,76,例4.22,使用循环产生如下图案(用户输入一个字母E时)ABACBADCBAEDCBAFEDCBA,77,例4.23,使用循环产生如下图案(用户输入一个字母E时)AABAABCBAABCDCBAABCDEDCBA ABCDEFEDCBA,78,总结,算法的描述方法:流程图 与基本控制结构相应的结构化的控制语句 if-else switch for while do-while break co
37、ntinue 常用算法,如累加、累乘、统计、递推、迭代、穷举等,79,常用算法 求阶乘: 数据类型的定义, long或double 求累加和: long 统计: 统计正数、平均分以上、n个成绩中10090、8980、7970、6960、60的人数;输入字符串中字母d的个数 设置一个计数变量k:初始化为1,每遇到一次将其加1:k+;,80,累加和 存放累加和的变量: 初始化为0或第一项,再循环加每一项; 循环控制: 前n项之和已知循环次数,可设置一个循环变量如i来控制; 加到某一项或累加和满足一定条件。例: 1+2+.+n 与 1+3+5+7+.和 2+4+6+8+.及12+32+52+72+ 输入n或累加和大于2000的最小的n,81,累加的项较复杂时,得专门求,例: 前后项之间无关: 1m+3m +5m +7m +. /4=1-1/3+1/5-1/7+.直到最后一项的绝对值小于10-6为止 前后项之间有关: 1!+2!+.+n! x0+x1 +x2+x3+. 1+1+2+3+5+8+13+21+. 2/1+3/2+5/3+8/5+13/8+21/13+. a+aa+aaa+aaaa+aaaaa+a是一个数字,例a=2,2+22+222+2222+,