版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第7章函数,内容提要,函数定义、函数调用、函数原型、函数的参数传递与返回值递归函数和函数的递归调用函数封装,函数复用,函数设计的基本原则,程序的健壮性变量的作用域与存储类型,全局变量、自动变量、静态变量、寄存器变量“自顶向下、逐步求精”的模块化程序设计方法,数学中的函数,自变量,因变量,函数名,程序设计中的函数,程序设计中的函数不局限于计算计算类,如打印阶乘表的程序判断推理类,如排序、查找,参数,返回值,问题的提出,读多少行的程序能让你不头疼?假如系统提供的函数printf()由10行代码替换,那么你编过的程序会成什么样子?实际上一个printf()有上千行代码main()中能放多少行代码?如
2、果所有代码都在main()中,怎么团队合作?如果代码都在一个文件中,怎么团队合作?,“事无巨细”,“事必躬亲”X,7.1分而治之与信息隐藏,分而治之(DivideandConquer,Wirth,1971)把较大的任务分解成若干个较小的任务,并提炼出公用任务:函数信息隐藏(InformationHiding,Parnas,1972)设计得当的函数可把具体操作细节对程序中无需知道它们的那些部分隐藏掉,从而使整个程序结构清楚使用函数时,不用知道函数内部是如何运作的,只按照我们的需要和它的参数形式调用它即可,7.2函数(function)的定义,函数是模块化编程的最小单位若干相关的函数可以合并成一个
3、“模块”一个C程序由一个或多个源程序文件组成一个源程序文件由一个或多个函数组成,7.2.1函数的分类,函数生来都是平等的,互相独立的,没有高低贵贱和从属之分main()稍微特殊一点点C程序的执行从main函数开始调用其他函数后流程回到main函数在main函数中结束整个程序运行,7.2.1函数的分类,标准库函数ANSI/ISOC定义的标准库函数符合标准的C语言编译器必须提供这些函数函数的行为也要符合ANSI/ISOC的定义第三方库函数由其它厂商自行开发的C语言函数库不在标准范围内,能扩充C语言的功能(图形、网络、数据库等)自定义函数自己定义的函数包装后,也可成为函数库,供别人使用,7.2.2函
4、数定义(Functiondefinition),类型函数名(类型参数1,类型参数2,)声明语句序列可执行语句序列return表达式;,返回值类型,函数名标识符,说明运算规则,参数表相当于运算的操作数,返回运算的结果,函数出口,7.2.2函数定义(Functiondefinition),类型函数名(类型参数1,类型参数2,)声明语句序列可执行语句序列return表达式;,参数表里的变量(叫形式参数,FormalParameter)也是内部变量,函数体,7.2.2函数定义(Functiondefinition),void函数名(void)声明语句序列可执行语句序列return;,函数无返回值,用v
5、oid定义返回值类型,用void定义参数,表示没有参数,return语句后无需任何表达式,【例7.1a】计算整数n的阶乘n!,/*函数功能:用迭代法计算n!函数入口参数:整型变量n表示阶乘的阶数函数返回值:返回n!的值*/longFact(intn)/*函数定义*/inti;longresult=1;for(i=2;i=n;i+)result*=i;returnresult;,返回值类型,函数名说明函数的功能,返回值作为函数调用表达式的值,形参表,函数入口,函数内部可以定义只能自己使用的变量,称内部变量,函数名(表达式1,表达式2,);实际参数(ActualArgument)函数调用(Foun
6、ctionCall)时提供的表达式中的参数有返回值时放到一个数值表达式中c=max(a,b);作为另一个函数调用的参数c=max(max(a,b),c);printf(%dn,max(a,b);无返回值时函数调用表达式display(a,b);,7.3向函数传值和从函数返回值,函数的参数传递,实参和形参必须匹配数目一致,类型一一对应(否则会发生自动类型转换),【例7.1】,例:交换两个数据。#includevoidmain()voidswap(int,int);inta,b;a=2,b=6;swap(a,b);printf(“a=%d,b=%d”,a,b);,voidswap(intx,int
7、y)inttemp;temp=x;x=y;y=temp;,a、b并未被交换。,函数的参数和返回值,实参和形参必须类型匹配形参也是一个变量,在函数被调用的时候分配空间当发生函数调用的时候,实参的值传递给形参通过返回值函数将值传回给调用的函数,返回值的类型由函数的返回类型决定一个函数最多只能有一条return语句,例:四舍五入#includeintround(floatx)x=x+0.5;returnx;voidmain()floata=2.7,b=3.4;inti,j;i=round(a);j=round(b);printf(“%i,%in”,i,j);,i,j,2.7,3.4,a,b,2.7,
8、x,3.2,3.4,3.9,3,3,7.3.2函数原型(FunctionPrototype),在调用函数前先声明其返回值类型、函数名和参数函数原型有助于编译器对函数参数类型的匹配检查,末尾有一个分号,声明时不要省略形参和返回值的类型,【例7.1】,函数定义与函数声明的区别,函数定义指函数功能的确立指定函数名、函数类型、形参及类型、函数体等是完整独立的单位函数声明是对函数名、返回值类型、形参类型的说明不包括函数体是一条语句,以分号结束,只起一个声明作用,7.3.3函数封装(Encapsulation),函数封装使得外界对函数的影响仅限于入口参数,而函数对外界的影响仅限于一个返回值和数组、指针类型
9、的参数,【例7.1】,Why?,传入负数的实参会怎样?,#includelongFact(intn);voidmain()intm;longret;printf(inputm:);scanf(%d,longFact(intn)inti;longresult=1;for(i=2;i=n;i+)result*=i;returnresult;,防御性程序设计(DefensiveProgramming),如何使函数具有遇到不正确使用或非法数据输入时避免出错的能力,增强程序的健壮性?在函数的入口处,检查输入参数的合法性,【例7.2】计算整数n的阶乘n!,longFact(intn)inti;longre
10、sult=1;if(n0)printf(Inputdataerror!n);elsefor(i=2;i=n;i+)result*=i;returnresult;,如何使函数具有遇到不正确使用或非法数据输入时避免出错的能力,增强程序的健壮性?在函数的入口处,检查输入参数的合法性,防御性程序设计(DefensiveProgramming),【例7.2】计算整数n的阶乘n!,主函数如何修改?增加对函数返回值的检验,防御性程序设计(DefensiveProgramming),【例7.3】计算整数n的阶乘n!,传入负数的实参时Fact()会返回-1吗?存在死代码的原因何在?,防御性程序设计(Defens
11、iveProgramming),【例7.3】计算整数n的阶乘n!,如何修改这个缺陷?如何保证不会传入负数实参?,防御性程序设计(DefensiveProgramming),【例7.2】计算整数n的阶乘n!,【例7.4】编写计算组合数的程序,函数复用,7.3.4函数设计的基本原则,信息隐藏,入口参数有效性检查敏感操作前的检查调用成功与否的检查,函数的嵌套调用,嵌套调用在调用一个函数的过程中,又调用另一个函数C语言规定函数不能嵌套定义,但可以嵌套调用函数是相互平行的,main()a();,a函数b();return;,b函数return;,7.4递归函数(RecursionFunction),7.
12、4.1递归的概念在函数当中又出现直接或者间接的调用该函数本身c的一个特色,直接递归:fun1()fun1();,间接递归:fun1()fun();,fun2()fun1();,例:有个人坐在一起,问第个人多少岁?他说比第个人大岁。问第个人岁数,他说比第个人大岁。问第个人,又说比第个人大岁。问第个人,说比第个人大岁。最后问第个人,他说是岁。请问第个人多大。,age(5)=age(4)+2age(4)=age(3)+2age(3)=age(2)+2age(2)=age(1)+2age(1)=10用数学公式表述如下:age(n)=10()age(n)=age(n-1)+2(),intage(intn
13、)*求年龄的递归函数*intc;*用作存放函数的返回值的变量*if(n=1)c=10;elsec=age(n-1)+2;return(c);,运行结果如下:,#includevoidmain()printf(“%d”,age(5);,7.4.2递归调用(RecursiveCall),longfact(intn)if(n0)return-1;elseif(n=0|n=1)return1;elsereturnn*fact(n-1);,【例7.6】计算n!=n*(n-1)*(n-2)*1,函数直接或间接调用自己,无需考虑n0了,7.4.2递归调用(RecursiveCall),unsignedlon
14、gfact(unsignedintn)if(n=0|n=1)return1;elsereturnn*fact(n-1);,基线情况(basecase),一般情况(generalcase),【例7.6】计算n!=n*(n-1)*(n-2)*1,递归调用其实是一种算法问题的解决需要通过有规律的调用同样的算法直到某些已知值或直接值通常可以抽象为函数:,7.4.2递归调用(RecursiveCall),递归调用应该能够在有限次数内终止递归递归调用若不加以限制,将无限循环调用必须在函数内部加控制语句,仅当满足一定条件时,递归终止,称为条件递归任何一个递归调用程序必须包括两部分递归循环继续的过程递归调用结
15、束的过程,if(递归终止条件成立)return递归公式的初值;elsereturn递归函数调用返回的结果值;,n!=n*(n-1)!(n-1)!=(n-1)*(n-2)!(n-2)!.(n-3)!5!:4!=4*3!3!=3*2!2!=2*1!1!=1,回推过程,递推过程,每个递归函数必须至少有一个基线条件一般情况必须最终能简化为基线条件,递归层数太多易导致栈空间溢出后果很严重,程序被异常中止,fact(5)=5*fact(4)=120fact(4)=4*fact(3)=24fact(3)=3*fact(2)=6fact(2)=2*fact(1)=2fact(1)=1,main,fact(5)
16、,fact(4),fact(3),fact(2),fact(1),递归与迭代,迭代即循环方法来编写的阶乘函数unsignedlongFact(unsignedintn)unsignedlongresult=1;unsignedinti;for(i=1;i=n;i+)result*=i;returnresult;递归程序遵循了数学中对阶乘的定义因此递归方法编写程序具有更清晰、可读性更好的优点,递归与迭代,1,1,2,3,5,8,.,longfib(intn)longf;if(n=0)f=0;elseif(n=1)f=1;elsef=fib(n-1)+fib(n-2);returnf;,【例7.7
17、】计算Fibonacci数列,递归与迭代,优点:从编程角度来看,比较直观、精炼,逻辑清楚符合人的思维习惯,逼近数学公式的表示尤其适合非数值计算领域hanoi塔,骑士游历、八皇后问题(回溯法)缺点:增加了函数调用的开销,每次调用都需要进行参数传递、现场保护等耗费更多的时间和栈空间应尽量用迭代形式替代递归形式,经典的汉诺(Hanoi)塔问题理解递归的概念,汉诺(Hanoi)塔问题,A,B,C,n=3,AB,AC,汉诺(Hanoi)塔问题,A,B,C,n=3,AB,AC,BC,,汉诺(Hanoi)塔问题,A,B,C,n=3,AB,AC,BC,AB,CA,CB,AB,汉诺(Hanoi)塔问题,A,B,
18、C,n=3,AB,AC,BC,AB,CA,CB,AB,汉诺(Hanoi)塔问题,A,B,C,n更大些怎么办?,n=3,AB,AC,BC,AB,CA,CB,AB,汉诺(Hanoi)塔问题,第1步:将问题简化假设A杆上只有2个圆盘,即汉诺塔有2层,n2将1号圆盘从A移到C将2号圆盘从A移到B将1号圆盘从C移到B,A,B,C,汉诺(Hanoi)塔问题,第2步:对于一个有n(n1)个圆盘的汉诺塔,将n个圆盘分为两部分:上面n-1个圆盘和最下面的n号圆盘。将“上面n-1个圆盘”看成一个整体将n-1个圆盘从A移到C将n号圆盘从A移到B将n-1个圆盘从C移到B,A,C,B,汉诺(Hanoi)塔问题,设计2个
19、函数:将n个圆盘借助C从A移到B将一个圆盘从A移到B,A,C,B,将n-1个圆盘从A移到C将n号圆盘从A移到B将n-1个圆盘从C移到B,汉诺(Hanoi)塔问题,递归方法的基本原理将复杂问题逐步化简,最终转化为一个最简单的问题最简单问题的解决就意味着整个问题的解决,汉诺(Hanoi)塔问题,7.5变量的作用域和存储类型,7.5.1变量的作用域(Scope)指在源程序中定义变量的位置及其能被读写访问的范围分为局部变量(LocalVariable)全局变量(GlobalVariable),局部变量(LocalVariable),在语句块内定义的变量形参也是局部变量特点生存期是该语句块,进入语句块时
20、获得内存,仅能由语句块内语句访问,退出语句块时释放内存,不再有效定义时不会自动初始化,除非程序员指定初值并列语句块各自定义的同名变量互不干扰形参和实参可以同名,全局变量(GlobalVariable),在所有函数之外定义的变量生存期是整个程序,从程序运行起占据内存,程序运行过程中可随时访问,程序退出时释放内存有效范围是从定义变量的位置开始到本程序结束,#includelongFib(inta);intcount;voidmain()intn,i,x;printf(Inputn:);scanf(%d,全局变量(GlobalVariable),【例7.8】打印计算Fibonacci数列每一项时所需
21、的递归调用次数,例外部变量与局部变量同名,#includeinta=3,b=5;voidmain()intmax(int,int);inta=8;printf(%d,max(a,b);intmax(inta,intb)intc;c=ab?a:b;return(c);,7.5.2变量的存储类型(StorageClass),指数据在内存中存储的方式即编译器为变量分配内存的方式,它决定变量的生存期存储类型数据类型变量名;C程序的存储类别auto型(自动变量)static型(静态变量)extern型(外部变量)register型(寄存器变量),静态存储区中的变量:与程序“共存亡”动态存储区中的变量:与
22、程序块“共存亡”寄存器中的变量:同动态存储区,变量的生存期(Lifetime)决定何时“生”,何时“灭”,7.5.2变量的存储类型(StorageClass),自动变量和静态变量,auto数据类型变量名;autointa;auto体现在进入语句块时自动申请内存,退出时自动释放内存动态局部变量,缺省的存储类型静态变量static数据类型变量名;staticinta;生存期为整个程序运行期间,#includevoidmain()intf(int);inta=2,i;for(i=0;i3;i+)printf(%d,f(a);intf(inta)autointb=0;intc=3;b=b+1;c=c+
23、1;return(a+b+c);,运行结果为:789,运行结果为:777,例考察静态局部变量的值,#includevoidmain()intf(int);inta=2,i;for(i=0;i3;i+)printf(%d,f(a);intf(inta)autointb=0;staticintc=3;b=b+1;c=c+1;return(a+b+c);,寄存器变量,寄存器CPU内部容量有限、但速度极快的存储器register类型名变量名;registerinti;使用频率比较高的变量声明为register,可使程序更小、执行速度更快现代编译器有能力自动把普通变量优化为寄存器变量,并且可以忽略用户的
24、指定所以一般无需特别声明变量为register,局部变量(内部变量)外部变量(全局变量)auto变量static变量register变量,C语言中的变量,局部变量只在本函数内部的当次调用有效全局变量在定义之后的所有区域有效静态变量默认初始化为0静态局部变量不释放,数据保留,#includeintg;intmain()voidstatictest(void);registerinti;intcount;staticintc;for(i=0;i5;i+)printf(寄存器变量i=%dn,i);printf(没有初始化的静态局部变量c=%dn,c);printf(全局变量g=%dn,g);for(
25、i=0;i5;i+)statictest();printf(局部变量count=%dn,count);printf(g=%dn,g);getchar();return0;,voidstatictest()staticintcount=0;printf(第%d次调用statictest函数!n,+count);g+;,全局变量,静态外部变量(只限本文件使用),外部变量(非静态外部变量允许其它文件引用),局部变量,自动变量,(离开函数,值就消失),寄存器变量(离开函数,值就消失),定义点之前使用,需用extern声明,静态局部变量(离开函数,值仍保留),动态局部变量,7.5变量的作用域与存储类型,
26、7.6模块化程序设计,模块各司其职每个模块只负责一件事情,它可以更专心便于进行单个模块的设计、开发、调试、测试和维护等工作一个模块一个模块地完成,最后再将它们集成开发人员各司其职按模块分配任务,职责明确并行开发,缩短开发时间什么时候需要模块化?某一功能,如果重复实现3遍以上,即应考虑模块化,将它写成通用函数,并向小组成员发布,7.6模块化程序设计,模块化的优点复用构建新的软件系统可以不必每次从零做起,直接使用已有的经过反复验证的软构件,组装或加以合理修改后成为新的系统,提高软件生产率和程序质量在其他函数的基础上构造程序拿来拿去主义,指尽可能复用其它人现成的模块不是人类懒惰的表现,而是智慧的表现一般要靠日积月累才能建立可以被复用的软件库前期投入多,缺乏近期效益,大部分公司都注重近期效益,是为了生存,所以软件复用对公司来说不是最高优先级,7.6模块化程序设计,功能分解自顶向下、逐步求精的过程模块分解的基本原则保证模块的相对独立性高聚合、低耦合模块的实现细节对外不可见信息隐藏外部:关心做什么;内部:关心怎么做设计好模块接口接口指罗列出一个模块的所有的与外部打交道的变量等定义好后不要轻易改动在模块开头(文件的开头)进行函
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026智能手臂训练器新物种:结合6G低延迟的远程实时康复指导
- 十五五跨境数据跨境服务金融开放:跨境支付数据合规创新
- 2026-2027学年初中心理健康九年级下册浙教版(边玉芳)10 职业万花筒课时同步卷
- 2026-2027学年初中心理健康九年级下册(2025)北师大版(2025)第八课 专心全攻略课时习题卷
- 2026中国视频号直播带货模式供需平衡用户体验及行业投资收益分析研究报告
- 2026年信息技术伦理:科目测模拟试卷及参考答案
- 2026年施工电梯模拟试卷带答案
- 2026年水利灌区考试题库及答案
- 2026年媒体素养模拟试卷及参考答案
- 2026年大二电路原理模拟试题(含答案)
- GB/T 12729.1-2026香辛料和调味品名称
- 2026广东深圳市交易集团限公司选聘28人易考易错模拟试题(共500题)试卷后附参考答案
- 2026年焊工技术比赛模拟试题(含答案)
- 第5课 生命最宝贵 课件(内嵌视频)2026-2027学年道德与法治四年级上册统编版
- 铁矿选矿技术概述培训课件
- 2026中国医生AI行为与态度调研报告抢先版
- 2026报关员面试题目及答案
- 小学一年级同音字大全(带拼音+组词+字义区分课本高频)
- 重庆航天科工集团笔试题
- 中国慢性肾脏病诊疗指南2025版
- 校园食品安全知识竞赛题库(附答案)
评论
0/150
提交评论