C语言程序设计:第八部分 基本程序设计技术

上传人:s9****2 文档编号:589927927 上传时间:2024-09-12 格式:PPT 页数:76 大小:1.17MB
返回 下载 相关 举报
C语言程序设计:第八部分 基本程序设计技术_第1页
第1页 / 共76页
C语言程序设计:第八部分 基本程序设计技术_第2页
第2页 / 共76页
C语言程序设计:第八部分 基本程序设计技术_第3页
第3页 / 共76页
C语言程序设计:第八部分 基本程序设计技术_第4页
第4页 / 共76页
C语言程序设计:第八部分 基本程序设计技术_第5页
第5页 / 共76页
点击查看更多>>
资源描述

《C语言程序设计:第八部分 基本程序设计技术》由会员分享,可在线阅读,更多相关《C语言程序设计:第八部分 基本程序设计技术(76页珍藏版)》请在金锄头文库上搜索。

1、1学习程序设计需要注意规律性的东西学习程序设计需要注意规律性的东西同一个问题可以采用不同的解决方案同一个问题可以采用不同的解决方案不同的解决方案具有不同的效率不同的解决方案具有不同的效率2第八部分第八部分基本程序设计技术基本程序设计技术3本部分内容本部分内容n基本程序设计技术基本程序设计技术q循环程序设计循环程序设计q解决问题的一些思路解决问题的一些思路q数据的精度数据的精度q程序调试程序调试4循环的常用机制循环的常用机制+,-将将变量值变量值加加/减减1。有前有前/后置写法:后置写法:+x x+将将x的值加的值加1-x x- 将将x的值减的值减1建议不要写难以理解的语句建议不要写难以理解的语

2、句,如如:Sum=(+a)+(+a);Printf(“%d%d%d”,a,a+,a+);1.增增/减量运算减量运算5形式:形式:表达式表达式1,表达式表达式2,表达式表达式3,表达式表达式4执执行行时时先先求求值值表表达达式式1,后后求求值值表表达达式式2,以以表表达达式式n的的值值作作为为整整个逗号表达式的值。个逗号表达式的值。优先级最低(低于赋值),从左向右结合。优先级最低(低于赋值),从左向右结合。主主要要用用在在for头头部部做做变变量量初初置置和和更更新新,用用于于做做多多个个变变量量赋赋值值或或更更新。例(求平方和):新。例(求平方和):for(sum=0, n=1; n=100;

3、 +n) sum = sum + n * n;2.逗号运算符逗号运算符( a=3*5,a*4), a+520x=(a=3,6*a) a=3x=1863.实现二元运算符操作的赋值运算符实现二元运算符操作的赋值运算符常见常见“sum = sum + n*n;”形式的赋值。形式的赋值。C语语言言为为许许多多二二元元运运算算符符提提供供了了(复复合合)赋赋值值符符。算算术术运运算符都有对应赋值运算符:算符都有对应赋值运算符:+=-=*=/=%= x+=y; 相当于相当于 x=x+(y); x*=y+z;?赋值运算符使用的例子(求平方和):赋值运算符使用的例子(求平方和):for (sum = 0, n

4、 = 1; n = 100; n+) sum += n * n;这些运算符的优先级与结合方式与普通赋值相同。这些运算符的优先级与结合方式与普通赋值相同。sum =sum+n * n74.循环中的几种变量循环中的几种变量循循环环中中常常出出现现几几类类变变量量,注注意意这这些些有有助助于于对对循循环环的的思思考和分析。考和分析。1)循环控制变量循环控制变量(循环变量循环变量):循环前设初值,循环中:循环前设初值,循环中递增递增/递减,达到递减,达到/超过界限时循环结束。它们控制循环超过界限时循环结束。它们控制循环的进行的进行/结束。结束。for中常有这类变量。中常有这类变量。for(n = 0;

5、 n = 0; -n) . .for(n = 2; n 52; n += 4) .这种循环是这种循环是固定次数固定次数的循环。的循环。82)累积变量累积变量:循环中常用:循环中常用+= 或或 *= 等更新。初值常用运算等更新。初值常用运算的单位元(加用的单位元(加用0;乘用;乘用1为初值)。循环结束时变量终值被为初值)。循环结束时变量终值被作为循环计算结果。作为循环计算结果。 sum+=t;3)递推变量:递推变量:对变量对变量x1、x2、x3,循环体可能有序列:,循环体可能有序列:x1 = x2;x2 = x3;x3 = . x1 . x2 .;9写循环时要考虑和解决问题写循环时要考虑和解决问

6、题:n循环涉及到哪些变量,需引进哪些临时性变量?循环涉及到哪些变量,需引进哪些临时性变量?n循环如何开始?循环开始前给变量什么初值?循环循环如何开始?循环开始前给变量什么初值?循环中变量的值如何改变?中变量的值如何改变?n什么情况下继续(或终止)循环?什么情况下继续(或终止)循环?n循环终止后如何得到所需结果?循环终止后如何得到所需结果?n用哪种结构实现循环,等等。用哪种结构实现循环,等等。工作方式工作方式:分析问题,发掘线索,最终完成程序。:分析问题,发掘线索,最终完成程序。10只有在程序设计实践中才能学好程序设计:只有在程序设计实践中才能学好程序设计:1)模仿好的范例;)模仿好的范例;2)

7、自己动手动脑,反复实践从问题出发做出程序的)自己动手动脑,反复实践从问题出发做出程序的整个过程;整个过程;3)多想想自己的程序做得怎么样,能不能做得更好。)多想想自己的程序做得怎么样,能不能做得更好。只有学会怎样只有学会怎样做好做好小程序,才能小程序,才能做出做出大程序大程序11学习程序设计需要注意规律性的东西。学习程序设计需要注意规律性的东西。三种流程模式是重要总结。三种流程模式是重要总结。本节主要内容:本节主要内容:n循环程序设计进阶循环程序设计进阶n顺序模式最简单顺序模式最简单n选择模式:要确定判断条件及不同情况下的动作选择模式:要确定判断条件及不同情况下的动作n难点是实现重复执行的循环

8、。难点是实现重复执行的循环。8.1循环程序设计循环程序设计 12138.1循环程序设计循环程序设计写循环首先要发现循环。写循环首先要发现循环。重复动作的常见实例:重复动作的常见实例:n一批类似数据做同样加工处理一批类似数据做同样加工处理n累积一批可按规律算出的数据(累加等)累积一批可按规律算出的数据(累加等)n反复从一个结果算出下一结果(递推)反复从一个结果算出下一结果(递推)n若重复次数若重复次数很多很多,就应该考虑用循环,就应该考虑用循环n如果重复次数如果重复次数无法确定无法确定,就必须用循环描述,就必须用循环描述14例例1:求:求13到到315所有数的平方根之和。所有数的平方根之和。可以

9、一个个地加,但更方便的方法是写循环。可以一个个地加,但更方便的方法是写循环。需要一个变量保存部分和,逐步把各平方根加上去;需要一个变量保存部分和,逐步把各平方根加上去;需要一个变量保存变动轨迹,从初值开始每次修改。需要一个变量保存变动轨迹,从初值开始每次修改。for(sum = 0.0, n = 13; n = 13; -n) sum += sqrt(n);典型典型for循环。假定已有总和变量循环。假定已有总和变量sum和循环变量和循环变量n:向上循环向上循环向下循环向下循环循环变量循环变量累积变量累积变量基本的循环方式有两种:向上循环和向下循环基本的循环方式有两种:向上循环和向下循环15wh

10、ile语句重写上例语句重写上例double sum;int n;Sum = 0.0; n = 13;while (n = 315) sum += sqrt(n); +n; 16注意注意:因为浮点计算存在误差,因为浮点计算存在误差,一般不用浮点数控制循一般不用浮点数控制循环环,尤其是增量为小数或包含小数时。,尤其是增量为小数或包含小数时。例:求从例:求从0到到100每隔每隔0.2的数的平方根之和:的数的平方根之和:double sum, x;for (sum=0.0, x=0.2; x=100.0; x+=0.2)sum += sqrt(x);由于浮点计算误差,不能保证循环由于浮点计算误差,不能

11、保证循环500次。次。应写:应写:int n; double sum;for (sum = 0.0, n = 1; n = 500; +n) sum += sqrt(0.2*n);17例例2:打印出打印出1到到200间的完全平方数。间的完全平方数。方法一方法一:逐个检查,遇平方数打印。循环框架:逐个检查,遇平方数打印。循环框架:for (n = 1; n = 200; n+) if (n是完全平方数是完全平方数) 打印打印 n;n是完全平方数判断是完全平方数判断:m可以从可以从1开始,递增,开始,递增,直至直至m*m大于大于n:for (m = 1; m * m = n; m+) if (m

12、* m = n) 打印打印 n;18完整程序:完整程序:#includeint main() int m, n;for(n=1; n = 200; n+)for (m = 1; m * m = n; m+) if (m * m = n) printf(%d , n);printf(n); return 0;内层循环结束的两种情况:内层循环结束的两种情况:1,找到,找到m使使m*m=n(n是完全平方数)是完全平方数)2,试探了所有可能,但都不成功(,试探了所有可能,但都不成功(n不是不是)共循环了多少次?共循环了多少次?19具有累计循环次数功能的完整程序:具有累计循环次数功能的完整程序:#inc

13、lude int main () int m, n, count = 0; for (n = 1; n = 200; n+) for (m = 1; m * m = n; m+) count+; if (m * m = n) printf(%d , n); printf(“%dn“, count); return 0;共循环了共循环了1799次次20方方法法二二:需需要要打打印印的的一一定定是是从从1开开始始连连续续几几个个整整数数的的平方,可从平方,可从1开始打印到平方大于开始打印到平方大于200为止。为止。for (n = 1; n * n = 200; +n) printf(%d , n

14、 * n); /*注意打印什么注意打印什么*/ 方法三方法三:还可以考虑利用递推公式:还可以考虑利用递推公式:方方法法一一产产生生所所有有备备选选数数据据(1到到200的的整整数数),检检查查排排除不合格的。除不合格的。生成与检查生成与检查是解决问题的常用方法。是解决问题的常用方法。方法二是针对具体问题的特定方法。方法二是针对具体问题的特定方法。21#includeint main() int termn, n; for (n = 1,termn = 1;termn = 200; n+) printf(%4d,termn); termn += 2*n+1; return 0;利用递推公式求平方

15、数程序利用递推公式求平方数程序:方法与启发方法与启发n方法方法1q产生所有备选数据(产生所有备选数据(1到到200之间的整数),检查排除不合格的。之间的整数),检查排除不合格的。n启发启发q生成与检查是解决问题的常用方法。生成与检查是解决问题的常用方法。n方法方法2q换个角度思考问题,是针对具体问题的特定方法。换个角度思考问题,是针对具体问题的特定方法。n方法方法3q递推,用数学模型解决问题递推,用数学模型解决问题n启发启发q同一个问题,可以有不同的解决方法同一个问题,可以有不同的解决方法q应尝试切换思考角度和寻找更有效的方法应尝试切换思考角度和寻找更有效的方法q不同的方法有不同的效率不同的方

16、法有不同的效率22例例3:判断整数是否为素数:判断整数是否为素数nint isprime(int),返回,返回0/1值值nn是素数当且仅当是素数当且仅当n没有真因子没有真因子q若若n % m = 0,则,则m是是n的因子的因子q若若n % m = 0,且,且 m n 23素数判断函数定义素数判断函数定义intisprime(intn)/*n是否素数是否素数*/ /intm=2;for(;m*m=n;m+)if(n%m=0)return0;/只要发现能被一个数整除,就返只要发现能被一个数整除,就返回回return1;/*没有因子,是素数没有因子,是素数*/ / 24分析分析n从循环中退出途径从循

17、环中退出途径q只要发现一个因子,就可做结论,只要发现一个因子,就可做结论,return 0;q没有发现因子,循环条件不符合。没有发现因子,循环条件不符合。n函数存在的问题函数存在的问题q对对1给出给出“是素数是素数” ;q负数也会给出不合理结果。负数也会给出不合理结果。n应该在循环前处理应该在循环前处理特殊情况特殊情况if (n = 1) return 0;n负数问题?负数问题?q如果需要可以另外考虑处理。如果需要可以另外考虑处理。2526例例4,艰难旅程(浮点误差)。乌龟要去环球。第,艰难旅程(浮点误差)。乌龟要去环球。第1秒爬秒爬1米,米,第第2秒爬秒爬1/2米,第米,第3秒爬秒爬1/3米

18、,第米,第4秒爬秒爬1/4米,米,。问一小时。问一小时能爬出多远?爬能爬出多远?爬20米需多少秒?米需多少秒?一小时能爬多远算法一小时能爬多远算法:1.d(距离距离,实数实数);s(时间时间,整数整数);2.d=0.0;s=1;3.d=d+1/(实数实数)s;s=s+1;4.如果如果s=3600,转转3;5.否则否则,输出输出d;爬爬20m需多少秒算法需多少秒算法:1.d(距离距离,实数实数);s(时间时间,整数整数);1.d=0.0,s=1;2.d=d+1/(实数实数)s;s=s+1;3.如果如果d20.0,转转3;4.否则否则,输出输出s-1;根据数学,乌龟能完成环球,可以爬得任意远。根据

19、数学,乌龟能完成环球,可以爬得任意远。这里想比较这里想比较float和和double的计算误差情况的计算误差情况。s-1?27n秒能爬秒能爬x米的函数米的函数float distfun(long n) float distfun(long n) long i; float x = 0.0; for (i = 1; i = n; +i) x += 1/(float)i; return x;例例4,艰难旅程(浮点误差)。乌龟要去环球。第,艰难旅程(浮点误差)。乌龟要去环球。第1秒爬秒爬1米,米,第第2秒爬秒爬1/2米,第米,第3秒爬秒爬1/3米,第米,第4秒爬秒爬1/4米,米,。问一小时能。问一小

20、时能爬出多远?爬爬出多远?爬20米需多少秒?米需多少秒?28例例4,艰难旅程(浮点误差)。乌龟要去环球。第,艰难旅程(浮点误差)。乌龟要去环球。第1秒爬秒爬1米,第米,第2秒爬秒爬1/2米,第米,第3秒爬秒爬1/3米,第米,第4秒爬秒爬1/4米,米,。问一小时能爬。问一小时能爬出多远?爬出多远?爬20米需多少秒?米需多少秒?20米需要多少时间。写出下面函数:米需要多少时间。写出下面函数:long scndsfun(float d) /*d为爬行距离为爬行距离*/ long i; float x = 0.0; for (i = 1; x d; +i) x += 1/(float)i; retur

21、n i - 1;d=2029写下面语句,执行时总也不输出:写下面语句,执行时总也不输出:printf(%lds, %fmn,scndsfun(20.),20.);修改为如下语句修改为如下语句:for (x = 10.0; x = 20.0; x += 1.0) printf(%lds, %fmn,scndsfun(x),x);原因?原因?程序输出:程序输出: 12367s, 10.000000m 33617s, 11.000000m 91328s, 12.000000m 248695s, 13.000000m 662167s, 14.000000m1673859s, 15.000000m而后又

22、没反应了。而后又没反应了。30void test_float () long i; float sum = 0.0, sum0 = -1.0; for (i = 1; sum != sum0; +i) sum0 = sum; sum += 1 / (float)i; printf (float: %ld terms at %fn, i-1, sum); 对乌龟活动的模拟受到数据表示精度和范围的限制。对乌龟活动的模拟受到数据表示精度和范围的限制。考虑如下的考虑如下的测试函数测试函数:程序很快就输出了一行:程序很快就输出了一行:float: 2097152 terms at 15.403683判断

23、爬的距离不再发生判断爬的距离不再发生变化。变化。Float精度限制精度限制,差差值无法测试到值无法测试到记住上一次的值记住上一次的值解决方案:改用双精度浮点数解决方案:改用双精度浮点数n如果把测试程序改用如果把测试程序改用double类型变量保存距离类型变量保存距离n则可以得出如下结果(则可以得出如下结果(15m以后)以后) 1835421s, 15m 2989191s, 16m 13562027s, 17m 36865412s, 18m111210581s, 19m272400600s, 20m采用采用float表示所爬的里程,表示所爬的里程,d d为目标里程为目标里程longscndsfu

24、n(floatd)longi;/秒数秒数 double x = 0.0; /已经爬里程已经爬里程for(i=1;x= 1E-6) x1 = x2; x2 = (2.0*x1 + x / (x1*x1) / 3.0; return x2;n程序的一个缺点是同一表达式写了两次。程序的一个缺点是同一表达式写了两次。调用语句调用语句:y=cbrt(200);或或x=200;y=cbrt(x);36do-while没有没有for和和while语句用得多。语句用得多。用用do-while结构重写求立方根结构重写求立方根函数:函数:double cbrt(double x) double x1, x2 =

25、x;if (x = 0.0) return 0.0; /*处理特殊情况处理特殊情况*/ do x1 = x2; x2 = (2.0*x1 + x / (x1*x1) / 3.0; while (fabs(x2 - x1) / x1) = 1E-6); return x2;37循环中的递推变量:循环中的递推变量:对变量对变量x1、x2、x3,循环体可能有序列:,循环体可能有序列:x1 = x2;x2 = x3;x3 = . x1 . x2 .;例如上面例如上面cbrt里的变量里的变量x1和和x2。38例例6:定义函数,利用公式:定义函数,利用公式求求近似值。设为近似值。设为double dsin

26、(double x)。sum = 0.0; 对对n为为0计算计算t;while (需要继续需要继续) sum = sum + t; 计算下一个计算下一个t;循环结束条件:循环结束条件:例如用项绝对值小于例如用项绝对值小于。方法:循环累加,方法:循环累加,n趋向无穷的过程中趋向无穷的过程中项值趋于项值趋于0,而,而累加值趋向函数值累加值趋向函数值。保存累加和的变量。保存累加和的变量sum,循环中,循环中求出的项值用求出的项值用t保存。保存。39问题:问题:t的值如何计算?的值如何计算?p第一个第一个t就是就是x;p分析可以发现项值的递推公式:分析可以发现项值的递推公式:double dsin(d

27、ouble x) double s=0.0, t=x; int n=0; /*n=0,t=x*/ while (t=1E-6|t=-1E-6) s+=t; n=n+1; t=-t*x*x/(2*n)/(2*n+1); return s;Sin(x)=x-x3/3!+x5/5!-x7/7!+.8.2循环中的重要问题循环中的重要问题 40nmisprime(m)isprime(n-m)验证结果6311OK58311OK510311OK511OK712310NO511OK7nmisprime(m)isprime(n-m)验证结果14311OK510711OK916311OK510OK710NO9.存

28、在多余存在多余判断判断for (n = 6; n = 200; n += 2) for (m = 3; m = n / 2; m+= 2) if (isprime(m) & isprime(n - m) printf(%d=%d+%dn, n, m, n-m);如何从循环中退出?如何从循环中退出?例:对例:对6200的各偶数验证哥德巴赫的各偶数验证哥德巴赫猜想(一个偶数可以拆成两个素数),猜想(一个偶数可以拆成两个素数),可以利用前面写的素数判断函数可以利用前面写的素数判断函数isprime41用用return退出?退出?n前面写前面写isprime时借助时借助return退出了函数,效退出了

29、函数,效果上等于结束了循环。果上等于结束了循环。n但是在这个程序里,程序判断完某个偶数但是在这个程序里,程序判断完某个偶数n已已经由某个素数对组成以后,还需要对下一个偶经由某个素数对组成以后,还需要对下一个偶数进行相同判断。数进行相同判断。n此时并不能用此时并不能用return结束函数的执行,怎么办结束函数的执行,怎么办?42解决方案解决方案1n增加对循环的控制,把发现素数分解作为条件加入。增加对循环的控制,把发现素数分解作为条件加入。n引入整型变量引入整型变量found,值,值0表示未发现素数对。发现时将表示未发现素数对。发现时将found赋赋1。内循环开始时。内循环开始时found置置0。

30、应修改内层循环条件。应修改内层循环条件。n修改后循环是修改后循环是for (n = 6; n = 200; n += 2) for (found = 0, m = 3; m = n / 2 & !found; m += 2) if (isprime(m) & isprime(n-m) printf(%d=%d+%dn, n, m, n - m); found = 1; 非常常用的机制,设置变量非常常用的机制,设置变量用于表示某一项任务的完成用于表示某一项任务的完成状态或某个对象的状态状态或某个对象的状态FoundNOTFound43执行过程示意执行过程示意nmfoundisprime(m)is

31、prime(n-m)found6301115183011151103011151230100501117114301115116301115118FoundNOTFound44解决方案解决方案2:用:用break语句语句n语法语法qbreak;n功能及说明功能及说明qbreak只能用在循环语句及只能用在循环语句及switch语句里。语句里。q用在循环语句里,从用在循环语句里,从break所处的循环层次的复合所处的循环层次的复合语句内跳出(跳到外层),程序中被跳出的循环语语句内跳出(跳到外层),程序中被跳出的循环语句体之后的第一条语句处继续执行。句体之后的第一条语句处继续执行。q用在用在swit

32、ch语句的语句体中时,从该语句体中跳出,语句的语句体中时,从该语句体中跳出,执行跳到执行跳到switch的语句体之后继续执行。的语句体之后继续执行。45例,用例,用break实现跳出实现跳出for (n = 6; n = 200; n += 2) for (m = 3; m = n / 2; m += 2) if (isprime(m) & isprime(n - m) printf(%d = %d+%dn, n, m, n - m); break; printf(“finished”);问题:执行完问题:执行完break以后执行哪以后执行哪条语句或计算?条语句或计算?expr2循环体循环体真

33、真( (非非0)for计算计算expr1计算计算expr3假假(0)46执行过程示意执行过程示意nmisprime(m)isprime(n-m)验证结果验证结果6311TRUE8311TRUE10311TRUE12310FALSE511TRUE14311TRUE16311TRUE1847利用利用break重写前面求立方根的函数重写前面求立方根的函数doublecbrt(doublex) doublex1,x2=x;if(x=0.0)return0.0;while(1)x1=x2;x2=(2.0*x1+x/(x1*x1)/3.0;if(fabs(x2-x1)/x1)1E-6)break;retu

34、rnx2; 本例中,因循环结束后函数不需要再做本例中,因循环结束后函数不需要再做别的事情,因此也可以在别的事情,因此也可以在break处直接处直接写写returnx2。解决了同一表达式计算写了两解决了同一表达式计算写了两段相类似的计算代码的问题段相类似的计算代码的问题48“常量常量”是标识符形式,在程序里代表同一常数的东西。是标识符形式,在程序里代表同一常数的东西。用用enum定义(定义(枚举枚举)可方便地定义一组符号常量:)可方便地定义一组符号常量:enum NUM = 10, LEN = 20; 枚举常量的作用?用于循环示例枚举常量的作用?用于循环示例例:例:#include enum S

35、TART = 0, END = 300, STEP = 20;int main (void) int c; for (c = START; c = END; c += STEP) printf(C = %d, F = %fn, c, c * 5.0/9.0 + 32.0); return 0; /*这样的程序更容易修改这样的程序更容易修改*/另一种形式:另一种形式:define START 0define END 300# define STEP 2049n符号形式表示能帮人理解程序意义。符号形式表示能帮人理解程序意义。n程程序序里里两两个个0可可能能代代表表不不同同意意义义,数数值值形形式式

36、没没有有任任何何区区分分。采用符号常量可提高可读性。采用符号常量可提高可读性。n将将所所需需常常数数定定义义为为符符号号常常量量,在在程程序序中中统统一一使使用用是是很很好好的的方方法。法。n使使程程序序更更容容易易修修改改(修修改改时时不不必必浏浏览览整整个个程程序序)。对对大大程程序序的作用更明显。的作用更明显。n课课本本第第五五章章继继续续介介绍绍其其他他常常量量定定义义方方式式。enum的的详详细细讨讨论论在在第九章,目前作为一种定义符号整型常量的机制。第九章,目前作为一种定义符号整型常量的机制。 说明:说明:508.3程序设计举例程序设计举例518.3程序设计实例程序设计实例例例1:

37、简单交互式计算器。:简单交互式计算器。假定它可以输入并计算:假定它可以输入并计算:128+365254+143810313+524 输入一行算一个结果。直至用户要求结束。输入一行算一个结果。直至用户要求结束。基本思想:基本思想: while (还有输入还有输入) 取得数据取得数据 计算并输出计算并输出用用scanf读数据,用文件结束或非数字表示输入结束。读数据,用文件结束或非数字表示输入结束。52#include int main () int left, right; printf(Small calculator.n); printf(Any no-digit character to s

38、top.n); while(scanf(%d, &left) = 1) if(getchar()!=+ | scanf(%d,&right)!=1) printf(Fmt error. Enter: nnn+mmmn ); while (getchar() != n); /丢掉本行剩余字符丢掉本行剩余字符 ; continue; printf(%d+%d=%dn,left,right,left+right); return 0;53例例2:单词计算问题单词计算问题 英文正文文件英文正文文件可看成是可看成是字符序列字符序列,空白字符空白字符把把序列分隔为一个个序列分隔为一个个“单词单词”。要求写

39、程序统计。要求写程序统计文件中的文件中的单词个数单词个数。 空白字符包括:空格空白字符包括:空格 、制表符、制表符t、换行符、换行符n54问题分析问题分析需要一个计数器,遇到一个词将计数器加一。需要一个计数器,遇到一个词将计数器加一。考虑用函数考虑用函数getchar读字符。程序主要部分的框架:读字符。程序主要部分的框架:while (文件未结束文件未结束) 遇到一个词遇到一个词时计数器加一时计数器加一;打印统计信息打印统计信息;用用getchar输入,很容易判断文件结束。输入,很容易判断文件结束。问题是如何确定问题是如何确定“遇到了一个词遇到了一个词”。55初始思路:初始思路:#includ

40、e int main () int c = , count = 0; while (c != EOF) while (c = getchar() != EOF & (c = | c = t | c = n) ; if (c = EOF) break; +count; while (c = getchar() != EOF & c != & c != t & c != n) ; printf(word count: %dn, count); return 0;读完新词读完新词略过空白字略过空白字符符出现新词56如何判断一个单词如何判断一个单词?n若读的字符是单词首字符,则计数器加一。若读的字符是

41、单词首字符,则计数器加一。n读入字符过程中需要区分是否空白。读入字符过程中需要区分是否空白。n问题:问题:q非空白字符未必是词的开始,是否新词要看前一字符是非空白字符未必是词的开始,是否新词要看前一字符是否空白。否空白。n可见:可见:q不能孤立地处理情况,要参考前面情况。不能孤立地处理情况,要参考前面情况。q必须做情况记录,以便后面参考。必须做情况记录,以便后面参考。57前后关系前后关系分两种情况:分两种情况:1)读到空白,随后遇非空白字符就是新词;)读到空白,随后遇非空白字符就是新词;2)读到非空白,随后不会遇到新词。)读到非空白,随后不会遇到新词。可看作处理过程的不同状态,可看作处理过程的

42、不同状态,两种状态两种状态:1)读在词外(遇到非空白是新词);)读在词外(遇到非空白是新词);2)读在词内。读在词内。在读入字符的过程中读入状态也不断转换。在读入字符的过程中读入状态也不断转换。典型,可以用有限状态转换系统(典型,可以用有限状态转换系统(自动机自动机)描述。)描述。58分析前后关系分析前后关系OUTIN读到空格字符读到空格字符状态不变状态不变读到非空格字符读到非空格字符转入词内状态转入词内状态读到空格字符读到空格字符转入词外状态转入词外状态读到非空格字符读到非空格字符状态不变状态不变两种读入状态:两种读入状态:OUT: 当前位置在词外当前位置在词外IN: 当前位置在词内当前位置

43、在词内在从在从OUT转换到转换到IN时,时,遇到新词,计数。遇到新词,计数。状态图转换图状态图转换图59状态的表示状态的表示60可以用一个变量来记录状态,设可以用一个变量来记录状态,设staten令变量取值为令变量取值为IN和和OUT;n只要求这两个值不同;只要求这两个值不同;n不会同时处在两种状态;不会同时处在两种状态;n可以将可以将IN, OUT定义成枚举值。定义成枚举值。if (c = | c = t | c = n) if (state = IN) state = OUT; else /* state为为OUT */ state = OUT;else /* 不是空格不是空格 */ if

44、 (state = IN) state = IN; else /* state为为OUT */ state = IN; +count; /* 许多地方可以简化许多地方可以简化 */61当前读状态变换的表示当前读状态变换的表示当前读到一个字符当前读到一个字符c时,处理可描述为:时,处理可描述为:#includeenumIN=1,OUT=0;intmain(void)intc,count=0,state=OUT;while(c=getchar()!=EOF)if(c=|c=t|c=n)/如果是空白字符如果是空白字符state=OUT;/在词外在词外elseif(state=OUT)/如果碰到非空白

45、字符如果碰到非空白字符/且读状态为在词外,则说明碰到新词且读状态为在词外,则说明碰到新词state=IN;/将状态修改为词内将状态修改为词内+count;/记数记数printf(wordcount:%dn,count);return0;62例例2:单词计算问题单词计算问题n英文正文文件可看成是字符序列,空白字符英文正文文件可看成是字符序列,空白字符(空格(空格 、制表符、制表符t、换行符、换行符n)把序列分隔为一个个)把序列分隔为一个个“单词单词”。要求。要求写程序统计文件中的单词个数。写程序统计文件中的单词个数。n思考思考q中文的词可以用这种办法找出来吗?中文的词可以用这种办法找出来吗?n拓

46、展学习拓展学习q学习中文分词知识及算法学习中文分词知识及算法638.4程序测试和排错程序测试和排错64分析问题分析问题编制程序编制程序编译编译连接连接调试运行调试运行完成完成调试中发现程序编写有调试中发现程序编写有错误,修改源程序错误,修改源程序编译时发现程序有语编译时发现程序有语法错误,修改源程序法错误,修改源程序连接时发现程序有错连接时发现程序有错误,修改源程序误,修改源程序调试运行时发现问题调试运行时发现问题分析设计有错误,重分析设计有错误,重新分析问题新分析问题程序开发过程程序开发过程658.4程序的调试与排错程序的调试与排错写好一个程序后,需要:写好一个程序后,需要:n通过加工(编译

47、和连接)产生可执行程序通过加工(编译和连接)产生可执行程序n运行它,提供数据进行试验,确认它确实满足要求运行它,提供数据进行试验,确认它确实满足要求n试验中常常会发现错误,需要设法排除试验中常常会发现错误,需要设法排除测试(测试(testing):在完成一个程序或一部分程序,通过编译后试):在完成一个程序或一部分程序,通过编译后试验性运行,仔细检查运行效果,设法确认该程序确实完成了所期验性运行,仔细检查运行效果,设法确认该程序确实完成了所期望的工作。反过来说:测试就是设法用一些特别选出的数据去挖望的工作。反过来说:测试就是设法用一些特别选出的数据去挖掘出程序里的错误掘出程序里的错误排错(排错(

48、debugging):在发现程序有错时,设法确认产生错误的):在发现程序有错时,设法确认产生错误的根源,修改程序,排除这些错误的工作过程根源,修改程序,排除这些错误的工作过程66测试的基本方法测试的基本方法测试时考虑的基本问题是提供什么样的数据,才可能测试时考虑的基本问题是提供什么样的数据,才可能最大限度地把程序中的缺陷和错误挖出来。最大限度地把程序中的缺陷和错误挖出来。有两类确定测试数据的基本方式:有两类确定测试数据的基本方式:1.根据程序结构确定测试数据。这相当于把程序打开,根据程序结构确定测试数据。这相当于把程序打开,根据其内部结构考虑如何检查它,设法发现其中的根据其内部结构考虑如何检查

49、它,设法发现其中的问题。这种方式称为问题。这种方式称为白箱测试白箱测试2.根据程序所解决的问题去确定测试过程和数据,不根据程序所解决的问题去确定测试过程和数据,不考虑程序内部如何解决问题。这相当于把程序看作考虑程序内部如何解决问题。这相当于把程序看作解决问题的解决问题的“黑箱黑箱”,因此称为,因此称为黑箱测试黑箱测试67白箱测试白箱测试考察程序内部结构及由此产生的执行流,选择数据使程考察程序内部结构及由此产生的执行流,选择数据使程序在试验运行中能通过序在试验运行中能通过“所有所有”可能出现的执行流程可能出现的执行流程1.复合结构只有一条执行流复合结构只有一条执行流2.“if(条件条件)语句语句

50、1else语句语句2”有两条可能执行流:条件成立有两条可能执行流:条件成立时执行时执行语句语句1;不成立时执行;不成立时执行语句语句2。应设法提供测试数据,检。应设法提供测试数据,检验程序在这两种情况下都能正确工作验程序在这两种情况下都能正确工作3.从本质上说从本质上说“while(条件条件)循环体循环体”可能产生无穷多条执行可能产生无穷多条执行流:循环体不执行,执行流:循环体不执行,执行1次,执行次,执行2次,次,。无法穷尽检。无法穷尽检查。查。常用方法是选择测试数据,检查循环的一些典型情况,常用方法是选择测试数据,检查循环的一些典型情况,包括循环体执行包括循环体执行0次、次、1次、次、2次

51、的情况,以及一些其他情况次的情况,以及一些其他情况其他结构可类似分析。要考虑程序中结构嵌套产生的组合流程其他结构可类似分析。要考虑程序中结构嵌套产生的组合流程68黑箱测试黑箱测试考虑的不是程序内部结构(可能是别人的程序,结构不可知;考虑的不是程序内部结构(可能是别人的程序,结构不可知;即使可知也可能极其复杂,无法理解其所有的执行流),只考即使可知也可能极其复杂,无法理解其所有的执行流),只考虑程序所解决问题的情况虑程序所解决问题的情况例如,如果某函数只有一个例如,如果某函数只有一个int参数,可检查参数为参数,可检查参数为0 0时结果是时结果是否正确,参数为否正确,参数为1 1和和-1-1时,

52、时,2 2和和-2-2怎么样等等怎么样等等如果对函数有所了解,还应考查已知结果的明显情况。例如对如果对函数有所了解,还应考查已知结果的明显情况。例如对求立方根函数,应先检查参数为求立方根函数,应先检查参数为0 0、1 1、-1-1、8 8、2727等的情况,等的情况,因为知道应该得到什么结果。确认这些情况都能正确工作后,因为知道应该得到什么结果。确认这些情况都能正确工作后,再去检查一些一般性情况再去检查一些一般性情况 69测试与驱动程序测试与驱动程序函数不是完整程序,怎样检查是否正确?函数不是完整程序,怎样检查是否正确?必须写临时主函数。测试用主函数(及辅助功能)称为必须写临时主函数。测试用主

53、函数(及辅助功能)称为驱动程序驱动程序或者或者测试台测试台。下面以测试立方根函数为例。下面以测试立方根函数为例。最容易想到的测试台可能是:最容易想到的测试台可能是:#include #include double cbrt(double x) int main () printf(%fn, cbrt(1.0);可检查发现语法错误等。可检查发现语法错误等。一个数据难以确认正确性,换数据需要改程序,麻烦。一个数据难以确认正确性,换数据需要改程序,麻烦。让程序帮助多做些事情。例如:让程序帮助多做些事情。例如:int main () double x, y; while (scanf(%lf, &x)

54、 = 1) printf(cbrt(%f) = %fn,x,cbrt(x); return 0;应该先试特殊情况和容易判断正误的情况:应该先试特殊情况和容易判断正误的情况:0cbrt(0.000000) = 0.0000001cbrt(1.000000) = 1.00000027cbrt(27.000000) = 3.0000001000cbrt(1000.000000) = 10.000000100cbrt(100.000000) = 4.64158971重复录入数据重复录入数据测试测试可能觉得反复试验和判断正误也很麻烦。可以写:可能觉得反复试验和判断正误也很麻烦。可以写:int main

55、() double x, y; for (x = -10.0; x 1E-10) printf(Error: x=%f, cbrt(x)=%fn, x, y); printf(Test finished.n); return 0;这里让计算机检查一系列计算。如果没有出错,程序只这里让计算机检查一系列计算。如果没有出错,程序只产生一行信息,报告程序完成。产生一行信息,报告程序完成。72排除程序中的错误排除程序中的错误n语法错误比较容易排错语法错误比较容易排错n排错语义错误(逻辑错误)时,要设法确定错排错语义错误(逻辑错误)时,要设法确定错误根源,确定程序在什么执行流中产生错误,误根源,确定程序在

56、什么执行流中产生错误,主要手段是选择适当的测试数据主要手段是选择适当的测试数据n测试程序、排除程序错误的最重要工具就是测试程序、排除程序错误的最重要工具就是眼眼睛和头脑睛和头脑n程序的良好格式极其重要程序的良好格式极其重要 排错常见方法排错常见方法1.设法确认程序对最基本的情况能正常工作设法确认程序对最基本的情况能正常工作2.解决了基本情况后再考虑更复杂的情况解决了基本情况后再考虑更复杂的情况3.设法找出出错的规律性,检查出错时数据经过的执行流,设法找出出错的规律性,检查出错时数据经过的执行流,逐步缩小可疑范围逐步缩小可疑范围4.在程序中加入输出语句,检查重要变量的值的变化情况在程序中加入输出语句,检查重要变量的值的变化情况5.利用利用IDE的排错功能的排错功能本部分应掌握的内容本部分应掌握的内容n程序设计基本过程程序设计基本过程n问题分析方法,从算法到程序问题分析方法,从算法到程序n程序的功能与性能要求程序的功能与性能要求n程序的错误处理和排错方法程序的错误处理和排错方法n程序的调试方法程序的调试方法n(黑箱、白箱)测试的概念(黑箱、白箱)测试的概念76QA!

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 高等教育 > 研究生课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号