540 likes | 690 Views
第三章 结构化程序设计. C 语句概述 选择结构 循环结构 顺序程序设计举例. §3.1 C 语句概述. 程序就是对计算机要执行的一组操作序列的描述。语句是高级语言源程序的基本组成单位。 语句按功能可以分为两类: 操作运算语句:用于描述计算机要执行的操作运算 ( 如赋值语句 ) , 流程控制语句:是控制上述操作运算的执行顺序 ( 如循环控制语句 ) 。. C 基本语句一览. 表达式语句. 表达式语句:由一个表达式后接一个分号组成的语句 ( 注意:没有分号的不是语句 ) 。 表达式语句可以分为以下四种基本类型:
E N D
第三章 结构化程序设计 C语句概述 选择结构 循环结构 顺序程序设计举例
§3.1 C语句概述 • 程序就是对计算机要执行的一组操作序列的描述。语句是高级语言源程序的基本组成单位。 • 语句按功能可以分为两类: • 操作运算语句:用于描述计算机要执行的操作运算(如赋值语句), • 流程控制语句:是控制上述操作运算的执行顺序(如循环控制语句)。
表达式语句 • 表达式语句:由一个表达式后接一个分号组成的语句(注意:没有分号的不是语句)。 • 表达式语句可以分为以下四种基本类型: • 赋值语句:由赋值表达式加一个分号组成。例如:x=sin(y); • 函数调用语句:由函数调用表达式后跟一个分号组成。例如:printf("hello,world\n"); • 空语句:是只有一个分号而没有表达式的语句。它不产生任何操作运算,只作为形式上的语句,被填充在控制结构之中。 • 一般表达式语句:例如:++x && ++y || ++ z;
流程控制语句 • 形成流程控制结构 • 分支结构:if …else 语句、switch 语句 • 循环结构: while 语句、do … while语句、for 语句 • 简单的流程转向。 • 限定转向: break、 continue、 函数调用、return • 非限定转向:goto语句
循环控制结构 • 循环控制结构一般由三部分组成: 进入条件、退出条件、循环体 • 循环控制结构可以分为三种形式: • while结构:退出条件是进入条件的“反条件”。即满足条件时进入,重复执行循环体,直到进入的条件不再满足时退出。 • do...while结构:无条件进入,执行一次循环体后再判断是否满足再进入循环的条件。 • for结构:和while结构类似,也是“先判断后执行”,但结构更紧凑。允许把初始化、修正、判断写在一起,使用起来更方便灵活,功能更强。
限定转向语句 • 这类语句不形成控制结构,只是简单地使流程从其所在处转向另一处。但是它不允许用户自己指定转向,而是按系统事先规定的原则向某一点转移。 C语言中属于这类的语句有三种: • break语句: 把流程从所在处转向所在的循环结构或多路选择结构之后,或者说是中止执行这些结构;
限定转向语句 • continue语句: 使本次循环体的执行提前结束(不再执行continue下面的语句),然后再根据循环条件是否满足,决定是否进入下次循环; • 函数调用和返回: 函数调用的功能是使流程转向所调用的函数体。return语句的功能是使流程从被调用函数返回主调函数。这两种流程控制都可能伴随有参数传递。
goto语句 • goto语句是一种使流程无条件转移的语句。它的作用是从所在处,转向本函数内的某一处,程序必须指出转向的目的地,目的地用标号指明。其语法形式为: goto 标号 • 标号应是合法的标识符。在作为转向目标的语句的前面要用同一标识符作为标号。 main() { int i,sum; i=1;sum=0 abc: sum = sum+i;i=i+1; if (i<100) goto abc; printf(“sum = %d”; sum); }
goto语句 • goto语句的无条件转向功能,若被无限制地滥用会导致程序结构不清晰。 • 结构化程序设计思想的提出就是从对它的批评开始的。为此曾在世界软件界引起一场大论战。最后结论是: • 多用goto语句是有害的,不提倡使用,但在某些情况下 (如能较大地提高运行效率,而又不破坏结构化原则)还是有用的; • 应当有限制地使用goto语句。 • 对初学者来说,应当养成不用goto语句的习惯。
复合语句 • C语言允许把一组语句括在一对花括号之中,称为复合语句。例如: main() { int a; … { int b; b=3; cout<<a+b<<endl; } … } • 注意,一个复合语句的后花括号之后不应再写分号。
复合语句 • 复合语句在语法上是一个整体,相当于一个语句。凡是能使用简单语句的地方,都可以使用复合语句。 • 一个复合语句中又可以包含另一个或多个复合语句(允许嵌套)。 • 复合语句中也可以定义变量,因此复合语句又称为分程序。在分程序中定义的变量,只在本分程序中有效。
顺序程序设计注意事项 • 变量必须先声明,然后才能使用; • 变量必须赋值后才能引用,否则得到的是一个随机不确定的值; • 赋值语句左边只能是变量名; • 程序中调用库函数时要在开头加上对其所在头文件的引用,如:#include “stdio.h”
顺序程序设计注意事项 • 输入语句中变量的值是在程序运行中才确定的,使用该值的语句必须在其后 • 自定义函数的“定义”在“调用”之前,调用前可不对函数声明,若定义在调用之后,调用前必须声明(函数头加分号);
§3.2 选择型结构 • 选择型程序所解决的问题称为判断问题,它描述的求解规则是:在不同的条件下所应进行的相应操作。 • 书写选择结构的步骤是: • 首先确定要判断的是什么条件 • 进一步再确定判断结果为不同的情况(“真”或“假”)时应该分别执行什么样的操作。 • C语言中可用三种语句来实现选择结构。
if(条件) else 条件式P N Y S1 语句A 语句B S2 if...else结构的应用 • if...else是选择型结构的基本形式。它构成如图所示的“二选一”控制结构。
例 求一个数的绝对值 • 设有任意数x,它的绝对值为 • 判断内容:x<0是否成立。 • 可能结果:①|x|=x (当x≥0) ②|x|=-x (当x<0)
X<0 是 否 |x|=-x |x|=x 例 求一个数的绝对值 • N-S图如右,C函数如下: double abstr(double x) { if(x<0.0) x=-x; else x=x; return(x); }
不平衡if结构 • C语言允许使用缺省else分结构的if…else结构,这种结构称为不平衡if结构。例如: double abstr(double x) { if(x<0.0) x=-x; return(x); } if (条件) 语句
if else的配对方法 • 当if嵌套时,从左至右进行,else总是与其最靠近但还未与其它else配对的if配对。 • if if if else else if else 例3.4 错误的三数中取大数函数 float max3 (float x, float y, float z) { float max = x; if (z>y) if (z>x) max = z; else if (y>x) max = y; return (max); }
使用不平衡if结构注意事项 float max3 (float x, float y, float z) { float max = x; if (z>y) {if (z>x) max = z; } else { if (y>x) max = y; } return (max); } 通过这个例子可以看到: • 不平衡的if...else结构会增加阅读和理解程序的困难。 • 正确的缩进格式(即锯齿形书写格式)可以帮助人们理解程序,但错误的缩进格式反而会使入迷惑。 • 不要太相信自己的判断,要严格按语法关系检查程序。在不易弄清的地方可以加花来保证自己构思的逻辑关系的正确性。
if(条件1) else if (条件2) … else if (条件n) else S1 S2 Sn Sn+1 else if 结构的应用 • else if 结构是if…else结构多重嵌套的一种变形, • 它的框架形式如图所示
else if 结构的应用 • else if结构是通过一连串的判断来寻找问题的解。它排列了一系列互相排斥的操作,每一种操作只有在相应的条件满足时才能执行(不一定执行)。 • 该结构开始执行后,依次对各条件进行判断测试,符合某一条件,则转去执行该条件下的操作,其它部分将被跳过;如无一条件为真,就执行最后一个else所指定的操作。这个else可以看作“其它”。 • 若最后一个else不存在,并且所有条件的测试均不成功,则该else if结构将不执行任何操作。
例:用else if 结构判断闰年 main() { int y; cout>>"input Year:"; cin>>y; if (y%4!=0) cout << y << "不是闰年! “ << endl; else if (y%400==0) cout << y << "是闰年! " << endl; else if (y%100==0) cout << y << "不是闰年! " << endl; else cout << y << "是闰年! " << endl; }
switch结构的应用 • switch结构与else if结构是多分支选择的两种形式。它们的应用环境不同:else if用于对多条件并列测试,从中取一的情形;switch结构用于单条件测试,从其多种结果中取一种的情形。
switch (整数表达式) { case (常量1): … case (常量n): default: } S1 Sn Sn+1 switch结构的应用 • switch结构的执行过程为:进入switch结构后,对条件表达式进行计算,然后从上至下去找与条件表达式的值相匹配的case语句,以此作为人口,执行switch结构中后面的各语句。
使用switch结构的注意事项 • 一个switch结构的执行部分是一个由一些case子结构与一个可缺省的default子结构组成的复合语句。要特别注意写一对花括号和case语句后的冒号“:”。 • switch后面的条件表达式一般是一个整数表达式(或字符表达式),与之相应,case后面应是一个整数或字符,或不含变量与函数的常数表达式。
使用switch结构的注意事项 • 表达式的值与case 后面的常量相等时,执行此case后的语句;若不遇到break语句,将继续执行后面其它case 和 default 所带的语句。若无匹配的case ,则执行default 后的语句。若又缺省 default,则相当于执行一个空语句。 • 一个switch结构中不可以出现两个case具有相同的常量表达式值。 • switch结构允许嵌套。
例:switch语句测试 main() { int n; cout << “\nInput a number: "; cin >> n; switch (n) { case 1: cout << “case1\t”; case 2: cout << “case2\t”; case 3: cout << “case3\t”; break; case 4: cout << “case4\t”; default: cout << “default\t”; } }
3.3 循环结构 • 循环是计算机解题的一个重要特征。计算机运算速度快,最宜于用于重复性的工作。 • 在程序设计时,人们也总是把复杂的不易理解的求解过程转换为易于理解的操作的多次重复。这样,一方面可以降低问题的复杂性,减低程序设计的难度,减少程序书写及输人的工作量;另一方面可以充分发挥计算机运算速度快、能自动执行程序的优势。 • 在循环算法中,穷举与迭代是两类具有代表性的基本应用。
穷举算法 • 穷举是一种重复型算法。它的基本思想是,对问题的所有可能状态一一测试,直到找到解或将全部可能状态都测试过为止。 • 循环控制有两种办法: • 计数法:要先确定循环次数,然后逐次测试,完成测试次数后,循环结束。 • 标志法:是达到某一目标后,使循环结束。 计数法使用起来很方便,但它要求在程序执行前必须先知道循环的总次数;当不想或无条件使用计数法时,可以使用标志法。
穷举算法举例 • 百鸡问题:鸡翁一值钱五,鸡母一值钱三、鸡雏三值钱一。百钱买百鸡,问鸡翁、母、雏各几何?它使用的是一个二重穷举算法:外层对公鸡数从0到19的范围内的每个值下的母鸡数、雏鸡数的组合进行测试,内层对母鸡数从0到33范围的每个值下的雏鸡数进行测试。两层循环结构所使用的都是计数法控制。 • 搬砖问题:36块砖,36人搬;男搬4,女搬3,两个小孩抬一砖。要求一次全搬完,问男、女、小孩各若干?
迭代算法 • 迭代是一个不断用新值取代变量的旧值,或由旧值递推出变量的新值的过程。迭代算法的主要因素是:初值、迭代公式、迭代次数。 • 例:人口增长问题:按年2%的增长速度,现有12亿人,10年后将有多少人? • 设现人口数为m,则一年后人口变为:m*(1+2%) • 第二年后,把上述赋值表达式再执行一次。要计算10年后的人口,就是把上述表达式执行10次。 • 这也要用循环结构实现,重复操作的内容是不断从一个变量的旧值出发计算它的新值。
迭代算法举例 • 兔子繁殖问题:设有一对新生兔子,从第三个月开始它们每个月都生一对兔子。按此规律,并假设没有兔子死亡,一年后共有多少对兔子。 • 每月的兔子数组成如下数列(Fibonacci数列): 1,1,2,3,5,8,13,21,34,… 从第3个数开始,每一个数都是其前面两个相邻数之和。 上述算法可以描述为: fibl=fib2=1 fibn=fib n-1+fib n-2 (n>=3) • 重复的条件为:3≤n<13,即n=3时进入,n=13时退出。如果要用计数法控制循环,则需要先算出到底是循环10次,还是11次的问题。
迭代算法举例 • 一元方程的迭代解法:用迭代法求一元方程 f(x)=0 的解,就是要把方程 f(x)=0,改写为一种迭代形式: x=φ(x)选取适当的初值x0(粗略的解),便可以通过重复迭代构造出一个序列: x0,x1,x2,… ,xn,… • 若这个数列收敛,即存在极限,且函数连续(在所求解的区间),则很容易很到: x*=lim xi (i→∞) • 这个极限值就是方程 f(x)=0 的一个解。 • 迭代不可能重复无穷多次。一般说来重复的次数应由指定的精确度(或误差)决定。当误差小于给定值时,便认为所得到的解足够精确了,迭代过程可以结束。 • 解一元方程常用的迭代方法有:二分法和牛顿法(切线法)
用goto语句构成循环 main() { int i,sum; i=1;sum=0 abc: sum = sum+i;i=i+1 if (i<100) goto abc; cout << “sum = ” << sum << endl; }
While结构的应用 • while是一种条件循环结构,其控制结构: • 在执行while语句时,先 对条件表达式进行计算, 若其值为真(非0),则执 行循环体中的语句,否 则跳过循环体,而执行该结构后面的语句。 • 在进入循环体后,每执行完一次循环体语句后,再对条件表达式进行一次计算和判断。当发现条件表达式的值为0时,便立即退出循环。 while(条件表达式) 循环体
例:百鸡问题求解 第一步: 设公鸡x,母鸡y, 小鸡z 0<= x <= 20 0<= y <= 33 0<= z <= 100 第二步: 1. 先固定公鸡数为0 2. 找出满足条件的 母鸡和小鸡数: x*5+y*3+z/3=100 3. 公鸡数+1,再作第2步 注:第2步中,母鸡又从0开始尝试,逐步+1,直到33…. 小鸡=100-公鸡-母鸡
main() /*百鸡问题*/ { int x=0,y,z; while (x<=20) { y=0; while (y<=33) { z=100-x-y; if (x*5.0+y*3.0+z/3.0==100) { cout << "cokes = “ << x << endl; cout << "hens = “ << y << endl; cout << "chicks = “ << z << endl; } y++; } x++; } }
do…while结构的应用 • 结构形式如图: • 当流程到达do后,立即执行循环体一次,然后才对条件表达式进行计算、测试。若条件表达式的值为真(非0),则重复执行一次循环体;否则退出。 • 与while结构相比,do…while结构至少要执行一次循环体。 do 循环体 while(条件表达式);
do…while结构的应用实例 /*将输入字符大小写颠倒*/ #include <stdio.h> main() { int c; do { c=getchar(); if (c>=‘a’ && c<=‘z’) c=c-32; else if (c>=‘A’ && c<=‘Z’) c=c+32; putchar(c); } while (c!=EOF); }
特点:先判断,后执行 特点:至少执行一次 循环体 条件式 n y 后续语句 条件式 循环体 后续语句 While 结构 Do…While 结构 n y
赋初值 y 达到终值? n 循环体 按步长增值 For结构的应用 • for语句是将初始化、条件判断、循环变量值变化三者组织在一起的循环控制结构。一般形式: For(表达式1;表达式2;表达式3) 循环体语句 • 这三个表达式的作用是控制循环,故称循环控制表达式。 • 表达式1称为初始化表达式;表达式2称为条件表达式;表达式3称为修正表达式。 for(初始化表达式;条件表达式;修正表达式) 循环体语句
For结构应用实例 main() /*打印九九乘法表*/ { int i,j; for (i=1; i<=9; i++) printf("%4d", i); printf("\n"); for (i=1; i<=36; i++) printf("%c", ’-’); printf("\n"); for (i=1; i<=9; i++) { for (j=1; j<=9;j ++) printf("%4d", i*j); printf("\n"); } } • 一个循环体内包含另一个完整的循环结构,称为循环嵌套 表头 分隔线 表 • 将9改为i可打印出三角九九乘法表
For结构应用实例 void sub1(int n) { int m; long a1=1, a2=1, b; printf("%ld%ld”, a1, a2); for (m=3; m<=n; m++) { b=a1+a2; a1=a2; a2=b; printf("%ld ",b); } return; } main()/*主函数*/ { int n; printf(“input n”); scanf("%d",&n); sub1(n); printf("\n"); } 兔子繁殖问题
Continue 与 break 用法比较 While ( ) { … break; … } While ( ) { … continue; … }
例6.9 求100~200之间的全部素数 #include <stdio.h> main() { int m, k, i, n=0; for ( m=101; m<+200; m+=2) { k=sqrt(m); for (i=2;i<=k; i++) if (m%i==0) break; if (i>=k+1) printf(“%d\t”,m); } printf(“\n”); }
循环的嵌套 • 一个循环体内又包含另一个完整的循环结构--循环的嵌套 • 各种循环可以相互嵌套 • 循环结构可以相互嵌套,但要注意不能相互交叉
几种循环结构的比较 • while 和do…while ,在循环体中包含使条件由真变假的语句(j++, j=j+1);For 循环可以在表达式3中包含使循环趋于结束的操作 • 用while 和do…while时,循环变量初始化的操作在while 语句之前完成;for 语句可以在表达式1中设置 • While和for 循环是先判断,后执行,而语句do…while循环是先执行,后判断