第7章函数.ppt

上传人:ga****84 文档编号:457611 上传时间:2018-10-09 格式:PPT 页数:67 大小:2.91MB
下载 相关 举报
第7章函数.ppt_第1页
第1页 / 共67页
第7章函数.ppt_第2页
第2页 / 共67页
第7章函数.ppt_第3页
第3页 / 共67页
第7章函数.ppt_第4页
第4页 / 共67页
第7章函数.ppt_第5页
第5页 / 共67页
点击查看更多>>
资源描述

1、第7章 函数,C语言程序设计,本章学习内容, 函数定义、函数调用、函数原型、函数的参数传递与返回值 递归函数和函数的递归调用 函数封装,函数复用,函数设计的基本原则,程序的健壮性 变量的作用域与存储类型,全局变量、自动变量、静态变量、寄存器变量 “自顶向下、逐步求精”的模块化程序设计方法,数学中的函数,自变量,因变量,函数名,程序设计中的函数,程序设计中的函数不局限于计算计算类,如打印阶乘表的程序判断推理类,如排序、查找,问题的提出,读多少行的程序能让你不头疼?假如系统提供的函数printf()由10行代码替换,那么你编过的程序会成什么样子?实际上一个printf()有上千行代码main()中

2、能放多少行代码?如果所有代码都在main()中,怎么团队合作?如果代码都在一个文件中,怎么团队合作?,问题的提出,三国演义中有这样一段描写:懿问曰:“孔明寝食及事之烦简若何?”使者曰:“丞相夙兴夜寐,罚二十以上皆亲览焉。所啖之食,日不过数升。”懿顾谓诸将曰:“孔明食少事烦,其能久乎?”此话音落不久,诸葛亮果然病故于五丈原。“事无巨细”,“事必躬亲” 管理学的观点是极其排斥这种做法的,认为工作必须分工,各司其职其中的思想,在程序设计里也适用,7.1分而治之与信息隐藏,分而治之( Divide and Conquer,Wirth, 1971 )函数把较大的任务分解成若干个较小的任务,并提炼出公用任

3、务信息隐藏(Information Hiding, Parnas, 1972)设计得当的函数可把具体操作细节对外界隐藏起来,从而使整个程序结构清楚使用函数时,不用知道函数内部是如何运作的,只按照我们的需要和它的参数形式调用它即可,程序设计的艺术,算法设计艺术程序的灵魂Donald E. Knuth,“The Art of Computer Programming”, 清华大学出版社(英),国防工业出版社(中)结构设计艺术程序的肉体模块化(Parnas, 1972)结构化(Structural)面向对象(Object-Oriented)面向组件(Component-Oriented)面向智能体(

4、Agent-Oriented),函数是C语言中模块化编程的最小单位可以把每个函数看做一个模块( Module )如把编程比做制造一台机器,函数就好比其零部件可将这些“零部件”单独设计、调试、测试好,用时拿出来装配,再总体调试。这些“零部件”可以是自己设计制造/别人设计制造/现成的标准产品,7.2 函数的定义,7.2 函数的定义,若干相关的函数可以合并成一个“模块”一个C程序由一个或多个源程序文件组成一个源程序文件由一个或多个函数组成,7.2.1函数的分类,函数生来都是平等的,互相独立的,没有高低贵贱和从属之分main( )稍微特殊一点点C程序的执行从main ( )函数开始调用其他函数后流程回

5、到main ( )函数在main ( )函数中结束整个程序运行,7.2.1函数的分类,标准库函数ANSI/ISO C定义的标准库函数符合标准的C语言编译器必须提供这些函数函数的行为也要符合ANSI/ISO C的定义第三方库函数由其他厂商自行开发的C语言函数库不在标准范围内,能扩充C语言的功能(图形、网络、数据库等)自定义函数自己定义的函数包装后,也可成为函数库,供别人使用,7.2.2函数的定义(Function Definition),类型 函数名(类型 参数1, 类型 参数2, )声明语句序列 可执行语句序列 return 表达式;,返回值类型,函数名标识符,说明运算规则,参数表相当于运算的

6、操作数,返回运算的结果,函数出口,类型 函数名(类型 参数1, 类型 参数2, ) 声明语句序列 可执行语句序列 return 表达式;,参数表里的变量(叫形式参数,Formal Parameter)也是内部变量,函数体,7.2.2函数的定义(Function Definition),void 函数名(void)声明语句序列 可执行语句序列 return;,函数无返回值,用void定义返回值类型,用void定义参数,表示没有参数,return语句后无需任何表达式,7.2.2函数的定义(Function Definition),【例7.1a】 计算整数n的阶乘n!,/* 函数功能: 用迭代法计算

7、n! 函数入口参数: 整型变量n表示阶乘的阶数 函数返回值: 返回n!的值*/long Fact(int n) /* 函数定义 */ int i; long result = 1; for (i=2; i=n; i+) result *= i; return result; ,返回值类型,函数名说明函数的功能,返回值作为函数调用表达式的值,形参表,函数入口,函数内部可以定义只能自己使用的变量,称内部变量,函数名(表达式1, 表达式2, );实际参数(Actual Argument )函数调用(Founction Call)时提供的表达式有返回值时放到一个数值表达式中 c = max(a,b);

8、作为另一个函数调用的参数 c = max(max(a,b),c); printf(%dn, max(a,b);无返回值时函数调用表达式 display(a,b);,7.3向函数传递简单变量的值和从函数返回值,函数的参数传递,实参和形参必须匹配数目一致,类型一一对应(否则会发生自动类型转换),【例7.1】,7.3.2函数原型(Function Prototype),在调用函数前先声明其返回值类型、函数名和参数函数原型有助于编译器对函数参数类型的匹配检查,末尾有一个分号,声明时不要省略形参和返回值的类型,【例7.1】,函数定义与函数声明的区别,函数定义指函数功能的确立指定函数名、函数类型、形参及类

9、型、函数体等是完整独立的单位 函数声明是对函数名、返回值类型、形参类型的说明不包括函数体是一条语句,以分号结束,只起一个声明作用,7.3.3函数封装与防御性程序设计,函数封装(Encapsulation)使得外界对函数的影响仅限于入口参数,而函数对外界的影响仅限于一个返回值和数组、指针类型的参数,【例7.1】,Why?,传入负数实参会怎样?,防御性程序设计(Defensive Programming),如何使函数具有遇到不正确使用或非法数据输入时避免出错的能力,增强程序的健壮性? 在函数的入口处,检查输入参数的合法性,【例7.2】 计算整数n的阶乘n!,如何使函数具有遇到不正确使用或非法数据输

10、入时避免出错的能力,增强程序的健壮性? 在函数的入口处,检查输入参数的合法性,防御性程序设计(Defensive Programming),【例7.2】计算整数n的阶乘n!,主函数如何修改?增加对函数返回值的检验,防御性程序设计(Defensive Programming),【例7.3】计算整数n的阶乘n!,传入负数的实参时Fact()会返回-1吗?存在死代码的原因何在?,防御性程序设计(Defensive Programming),【例7.3】计算整数n的阶乘n!,如何修改程序去除冗余代码?如何保证不会传入负数实参?,防御性程序设计(Defensive Programming),【例7.2】

11、计算整数n的阶乘n!,【例7.4】编写计算组合数的程序,函数复用,7.3.4函数设计的基本原则,信息隐藏,入口参数有效性检查敏感操作前的检查调用成功与否的检查,函数的嵌套调用,嵌套调用在调用一个函数的过程中,又调用另一个函数C语言规定函数不能嵌套定义,但可以嵌套调用函数是相互平行的,main()a();,a 函数b();return;,b函数return;,7.4 函数的递归调用和递归函数,如果一个对象部分地由它自己组成或按它自己定义,则我们称它是递归(Recursive)的。生活中,字典就是一个递归问题的典型实例字典中的任何一个词汇都是由“其他词汇”解释或定义的,但是“其他词汇”在被定义或解

12、释时又会间接或直接地用到那些由它们定义的词递归方法的基本原理将复杂问题逐步化简,最终转化为一个最简单的问题最简单问题的解决就意味着整个问题的解决,递归函数(Recursive Function),long fact(int n) if (n 0) return -1; else if (n = 0 | n = 1) return 1; else return n * fact(n-1); ,【例7.5】计算n!= n *(n-1)*(n-2)*1,函数直接或间接调用自己,称为递归调用(Recursive Call),递归函数(Recursive Function),unsigned long

13、fact(unsigned int n) if (n = 0 | n = 1) return 1;else return n * fact(n-1); ,基线情况(base case),一般情况(general case),无需考虑n0了,【例7.5】计算n!= n *(n-1)*(n-2)*1,递归函数(Recursive Function),递归调用应该能够在有限次数内终止递归递归调用若不加以限制,将无限循环调用必须在函数内部加控制语句,仅当满足一定条件时,递归终止,称为条件递归任何一个递归调用程序必须包括两部分递归循环继续的过程递归调用结束的过程,if (递归终止条件成立) return

14、 递归公式的初值; else return 递归函数调用返回的结果值;,n!=n(n-1)! (n-1)!=(n-1)(n-2)! (n-2)! (n-3)! 5! 4!=43! 3!=32! 2!=21! 1!=1,回推过程,递推过程,每个递归函数必须至少有一个基线条件一般情况必须最终能简化为基线条件,递归层数太多易导致栈空间溢出后果很严重,程序被异常中止,fact(5)=5*fact(4)= 120 fact(4)= 4*fact(3)= 24 fact(3)= 3*fact(2)= 6 fact(2)= 2*fact(1)=2 fact(1)=1,main,fact(5),fact(4)

15、,fact(3),fact(2),fact(1),递归与迭代,用迭代(即循环)方法编写的阶乘函数unsigned long Fact(unsigned int n) unsigned long result = 1; unsigned int i; for (i = 1; i = n; i+) result *= i; return result;递归程序遵循了数学中对阶乘的定义因此递归方法编写程序具有更清晰、可读性更好的优点,递归与迭代,1,1,2,3,5,8,.,long Fib(int n)long f;if (n = 0) f = 0;else if (n = 1) f = 1;els

16、e f = Fib(n-1) + Fib(n-2);return f;,【例7.6】计算Fibonacci数列,递归与迭代,优点:从编程角度来看,比较直观、精炼,逻辑清楚符合人的思维习惯,逼近数学公式的表示尤其适合非数值计算领域hanoi塔,骑士游历、八皇后问题(回溯法)缺点:增加了函数调用的开销,每次调用都需要进行参数传递、现场保护等耗费更多的时间和栈空间应尽量用迭代形式替代递归形式,7.5变量的作用域和存储类型,7.5.1变量的作用域 ( Scope )指在源程序中定义变量的位置及其能被读写访问的范围分为局部变量(Local Variable) 全局变量(Global Variable )

17、,局部变量( Local Variable ),在语句块内定义的变量形参也是局部变量特点生存期是该语句块,进入语句块时获得内存,仅能由语句块内语句访问,退出语句块时释放内存,不再有效定义时不会自动初始化,除非程序员指定初值并列语句块各自定义的同名变量互不干扰 形参和实参可以同名,全局变量( Global Variable ),在所有函数之外定义的变量生存期是整个程序,从程序运行起占据内存,程序运行过程中可随时访问,程序退出时释放内存有效范围是从定义变量的位置开始到本程序结束,全局变量( Global Variable ),【例7.7】打印计算Fibonacci数列每一项时所需的递归调用次数,全

18、局变量使函数间的数据交换更容易,更高效,但建议尽量少用,因为谁都可改写它,所以很难确定是谁改写了它,7.5.2变量的存储类型( Storage Class),指数据在内存中存储的方式即编译器为变量分配内存的方式,它决定变量的生存期 存储类型 数据类型 变量名;C程序的存储类别auto型(自动变量)static型(静态变量)extern型(外部变量)register型(寄存器变量),静态存储区中的变量:与程序“共存亡” 动态存储区中的变量:与程序块“共存亡” 寄存器中的变量: 同动态存储区,变量的生存期(Lifetime )决定何时“生”,何时“灭”,7.5.2变量的存储类型( Storage

19、Class),auto 数据类型 变量名;auto体现在进入语句块时自动申请内存,退出时自动释放内存动态局部变量,缺省的存储类型静态变量 static 数据类型 变量名;static storage class for local variables (declared inside a block or function) - the lifetime of the entire program生存期为整个程序运行期间,自动变量和静态变量,自动变量和静态变量,【例7.9】,自动变量不初始化时,值是随机值,静态局部变量和全局变量自动初始化为0值,【例7.10】利用静态变量计算整数n的阶乘n!,

20、自动变量和静态变量,静态变量仅初始化一次,变量的值可保存到下次进入函数,使函数具有记忆功能,寄存器变量,寄存器CPU内部容量有限、但速度极快的存储器 register 类型名 变量名; 使用频率比较高的变量声明为register ,可使程序更小、执行速度更快现代编译器有能力自动把普通变量优化为寄存器变量,并且可以忽略用户的指定所以一般无须特别声明变量为register,全局变量,静态外部变量 (只限本文件使用),外部变量 (非静态外部变量,允许其他文件引用),局部变量,自动变量,(离开函数,值就消失),寄存器变量(离开函数,值就消失),定义点之前使用,需用extern声明,静态局部变量 (离开

21、函数,值仍保留),动态局部变量,7.5变量的作用域和存储类型,7.6模块化程序设计,模块各司其职每个模块只负责一件事情,它可以更专心便于进行单个模块的设计、开发、调试、测试和维护等工作一个模块一个模块地完成,最后再将它们集成开发人员各司其职按模块分配任务,职责明确并行开发,缩短开发时间什么时候需要模块化?某一功能,如果重复实现3遍以上,即应考虑模块化,将它写成通用函数,并向小组成员发布,7.6模块化程序设计,模块化的优点复用构建新的软件系统可以不必每次从零做起,直接使用已有的经过反复验证的软构件,组装或加以合理修改后成为新的系统,提高软件生产率和程序质量在其他函数的基础上构造程序拿来拿去主义,

22、指尽可能复用其他人现成的模块不是人类懒惰的表现,而是智慧的表现一般要靠日积月累才能建立可以被复用的软件库前期投入多,缺乏近期效益,大部分公司都注重近期效益,是为了生存,所以软件复用对公司来说不是最高优先级,7.6模块化程序设计,功能分解自顶向下、逐步求精的过程模块分解的基本原则保证模块的相对独立性高聚合、低耦合模块的实现细节对外不可见信息隐藏外部:关心做什么;内部:关心怎么做设计好模块接口接口指罗列出一个模块的所有的与外部打交道的变量等 定义好后不要轻易改动在模块开头(文件的开头)进行函数声明,7.6模块化程序设计,逐步求精(Stepwise Refinement)由不断的自底向上修正所补充的

23、自顶向下(Top-down)的程序设计方法,【例7.11】用函数完成猜数游戏,猜多个数,10次猜不对就猜下一个数模块分解过程,开始,结束,初始化,退出处理,主功能,为程序运行所做的准备工作,在退出前要做的事情,如打印结果、资源释放等,自底向上,自顶向下的模块化程序设计,【例7.11】用函数完成猜数游戏,开始,结束,生成数字,猜数字,【例7.11】用函数完成猜数游戏,开始,结束,生成数字,猜数字,是否继续?,N,Y,【例7.11】用函数完成猜数游戏,开始,结束,猜得对吗?,N,Y,提示大小,次数= MIN_NUMBER ,使用断言(Assert)防止某些参数获得非法值,在程序调试和测试时发现错误

24、,#include void assert(int expression);expression为真,无声无息;为假,中断程序断言仅用于调试程序,不能作为程序的功能,断言,用来测试某种不可能发生的状况确实不会发生Debug版有效Release版失效考虑使用断言的几种情况检查程序中的各种假设的正确性证实或测试某种不可能发生的状况确实不会发生,程序版式,缩进(Indent)保证代码整洁、层次清晰的主要手段良好风格的程序应严格采用梯形层次对应好各层次,int IsPrime(int n) int k, i; k = sqrt(double)n); for (i=2; i=k; i+) if (n %

25、 i = 0) return 0; return 1;,#include main() int i; for (i=2; i100; i+) if (IsPrime(i) printf(%dt,i); ,程序版式,现在的许多开发环境、编辑软件都支持自动缩进根据用户代码的输入,智能判断应该缩进还是反缩进,替用户完成调整缩进的工作VC中有自动整理格式功能只要选取需要的代码,按ALT+F8就能自动整理成微软的cpp文件格式,命名规则,在Linux/UNIX平台习惯用function_name 本书采用Windows风格函数名命名用大写字母开头、大小写混排的单词组合而成 FunctionName 变量名形式“名词”或者“形容词+名词”如oldValue与newValue等函数名形式“动词”或者“动词+名词”(动宾词组)如GetMax()等,对函数接口进行注释说明,/* 函数功能:实现功能 函数参数:参数1,表示 参数2,表示 函数返回值: */返回值类型 函数名(形参表)return 表达式;,挑战性的作业挑战类型表示的极限 50位的n!计算?大数的存储问题,作业,习题7.1 7.6实验题本章实验题 2.,Questions and answers,

展开阅读全文
相关资源
相关搜索
资源标签

当前位置:首页 > 学术论文资料库 > 毕业论文

Copyright © 2018-2021 Wenke99.com All rights reserved

工信部备案号浙ICP备20026746号-2  

公安局备案号:浙公网安备33038302330469号

本站为C2C交文档易平台,即用户上传的文档直接卖给下载用户,本站只是网络服务中间平台,所有原创文档下载所得归上传人所有,若您发现上传作品侵犯了您的权利,请立刻联系网站客服并提供证据,平台将在3个工作日内予以改正。