收藏 分销(赏)

c++第六章.ppt.ppt

上传人:s4****5z 文档编号:14015083 上传时间:2026-05-27 格式:PPT 页数:52 大小:402KB 下载积分:10 金币
下载 相关
c++第六章.ppt.ppt_第1页
第1页 / 共52页
c++第六章.ppt.ppt_第2页
第2页 / 共52页


点击查看更多>>
资源描述
第6章 函数,6.1 函数的定义,6.2 函数的参数,6.3 函数的返回值,6.4 函数的原型说明,6.5 函数的调用,6.6 作用域和存储类型,6.7,C+,增加的函数特性,作业:6,7,8,12,13,16,18,6.1 函数的定义,函数,:功能独立的语句块。,需先定义后使用,。函数分为库函数和自定义函数。,main,函数,:系统约定,用户定义,有且仅有一个,程序执行的唯一入口,由操作系统调用。,main,函数通过调用库函数或自定义函数实现程序的功能。,库函数(预定义函数),:,C+,编译系统、操作系统或其它系统为方便用户程序设计而预定义的函数。使用库函数可简化程序,提高编程效率。,用户自定义函数,:用户编写、完成特定功能的函数。,函数定义格式,(),/函数头,/函数体,可为任何已定义数据类型,。,若省略,则默认是,int,型。,若无返回值,则其类型应用,void,说明。,应见名知意。,函数体:用一对花括号“”括起的块语句。即使函数体内没有语句,花括号“”也不可省。,函数体内不能包含其它函数的定义。,指明每个参数的类型和名称,参数间用逗号分隔。,若无参数,则用()或(,void),说明。,参数列表是函数调用时数据传递的接口。函数定义时的参数称为,形式参数,,函数调用时的参数称为,实际参数,。,函数定义时,圆括号后不能加分号,“,;,”,。,有参且有返回值。,如:,int,max(int,a,int,b)return(ab)?a:b;,有参但无返回值。,如:,void,swap(int,x,int,y),int,t=x;x=y;y=t;,无参但有返回值。,如:,char,getc,(),char x;,cin,x;return x;,无参也无返回值。,如:,void mess(),cout,”,你好,欢迎学习,C+!”;,函数定义举例,6.2 函数的参数,函数的形式参数简称形参。,当被调函数有参时,主调函数和被调函数之间通过形参实现数据传递。,函数的形参仅在函数被调用时,才由系统分配内存,用于接收主调函数传递来的实际参数。,函数的实际参数简称实参。,函数调用时实参的类型应与形参的类型一一对应。,实参应有确定值,可为常量、变量或表达式。,函数调用时系统才为,形参,分配内存,,与实参占用不同的内存,,即使形参和实参同名也不会混淆。函数调用结束时,形参所占内存即被释放。,6.3 函数的返回值,函数的返回值:由被调函数计算处理后向主调函数返回的计算结果,,最多只能一个,,用,return,实现。,无返回值的函数其返回值类型应说明为,void,类型,否则将返回一个不确定的值。,Return,的两种格式:,return;,/用于带有返回值的函数,return;,/,用于无返回值的函数,在执行被调函数时,遇到,return,语句就结束函数的执行,返回到主调函数。若函数中无,return,语句,会执行到函数体最后的”为止,返回到主调函数。,若函数有多个返回分支,则应保证每个分支均有确定的返回值,否则可能出现逻辑错误。,例如:,char,toLower(char,c),if(c=A&c=A&c=Z),return c+a-A;,return c;,/,或:,else return c;,6.4,函数原型,函数后定义先使用是常见现象,如:,自顶向下、逐步求精的程序设计方法,使程序员习惯将,main,函数作为程序的第一个函数。这样在,main,函数中可能调用其后定义的许多函数。,程序由多个文件组成时,若一个文件中的函数要调用另一个文件中的函数时,也会出现类似问题。,使用库函数。,函数原型的作用:使函数能后定义先使用。,函数原型的含义:对定义在后或库中的函数,在使用前做声明,包括函数名、返回类型及参数类型。,(),;,函数原型与函数定义在返回类型、函数名和参数类型方面必须一致。,库函数的原型通常在头文件中声明,在编程时,若要使用某个头文件中的库函数,则必须先将这个头文件包含到程序中。,函数原型中说明的标识符,可与其,定义,不同,,例,如:,float,f(int,x,float,y,);/f(),的原型说明,float,f(int,a,float,b,)/f(),的定义,return a+b;,函数原型中说明的标识符也可省略,例如:,float,f(int,float,);,函数原型的格式:,6.5 函数的调用,格式:,(),说明:,当调用一个函数时,其实参的个数、类型及排列次序必须与函数定义时的形参一致。对于无形参的函数,调用时实参表为空。,函数调用的方式:,语句调用、表达式调用,无返回值的函数只能用函数调用语句来调用。,在不需要利用返回值时,有返回值的函数也可用函数调用语句来调用。,若函数有返回值,则函数调用可出现在表达式中,使函数的返回值参与表达式的运算。,函数调用时,实参向形参传递参数的,方式有三种,:,值传递,也称传值。,形式:,形参为普通变量,实参为表达式,实参向形参赋值。,特点,:,参数传递后,实参和形参不再有任何联系。,注意:,实参是表达式,故形参不可能给实参赋值。,引用传递,也称传引用。,形式:,形参为引用型变量,实参为变量,实参为引用型形参初始化。,特点:,参数传递后,形参是实参的别名,彼此关联。,指针传递,也称传指针。,形式:,形参为指针变量,实参为指针,表达式,。,特点:,参数传递后,形参可读写实参所指的存储空间。,6.5.1函数的传值调用,例6.4:传值调用时两个数的交换,P72,传值调用的优点:,函数调用对,其外界的变量,无影响,最多只能用,return,返回一个值,函数独立性强。,(,P72,例6.5),6.5.2函数的引用调用,引用,-变量的别名。对别名的访问就是对别名所关联变量的访问,反之亦然。例如:,int,i;,int,&,ai,=i;/,定义,int,型引用,ai,是变量,i,的别名,ai,=15;/,此时,i,的值也为15,使用引用应注意:,定义引用时,应同时对它初始化,使它与一个类型相同的已有变量关联;,一个引用与某变量关联,就不能再与其它变量关联。,引用主要用作函数的形参和返回值,。,例:,P73 6.6,6.5.3 函数调用过程分析,6.5.4函数的嵌套调用,C+,不允许函数的嵌套定义,。但,允许函数的嵌套调用,。,例6.7 计算1,k,+2,k,+3,k,+,+,n,k,。,上机问题总结,1,、对,为什么要函数,不清楚,求某个数的绝对值、求,x,n,、对某个数开平方、比较给出两个数的最大值、求,n!,、判断某个给定数是否是素数,2,、对函数怎么写不清楚,具体表现在:要什么样的返回值,传什么样的形参,3,、对引用作形参的作用不清楚,4,、出现在,main,函数中再定义函数的现象,5,、对函数的调用过程不清楚,6,、对变量的作用域不明白,想访问就访问,6.5.5函数的递归调用,函数的,递归调用,:一个函数直接或间接调用本身。,例:求4!。,分析:通常有两种求法。,递推法,由已知开始,逐步递推求解,最终求得未知。,由1!=1,求得2!=1!*2=1*2=2;再由2!=2,求得3!=2!*3=2*3=6;最后,由3!=6,求得4!=3!*4=6*4=24。,递归法:,将,n!,转换为:,求4,!,的递归程序:,#,include,int,f(int,n),if(n=1|n=0,),return 1;/A,else return n*f(n-1);/B,int,main(void),cout,4!=f(4)n;,return 0;,递归调用本质上是嵌套调用,只不过是嵌套调用自身。,递归函数的执行包括递推和回归两个过程。,从递归函数,f,的代码和其执行过程看,尽管函数体只使用,if,分支结构,代码非常简单,但通过递归调用隐式实现了循环。,正是通过递归调用将循环隐藏起来,大大简化了算法的表达。,递归法解决问题的关键:,善于归纳问题的递归特征:将原问题转化为一个新问题,而这个新问题与原问题有相同的解决方法。继续这种转化,直到转化出来的问题是一个有已知解的问题为止。例如,,n!,可转化为,n*(n-1)!,,最终,1!=1,。,善于分析和总结问题的递归求解结束条件:只有有限次递归才有实际意义。例如,求,n!,时,,n,为,1,或,0,是递归结束条件。,例,6.10,输入一个整数,逐位正序和反序输出。如输入,3456,,则输出,3456,和,6543,。分别设计两个函数,一个实现正序输出,另一个实现反序输出。,分析:如何,从右往左,(或,从左往右,)得到每一个数。然后再进行显示,解决:从右往左思考,将问题转换为求余问题,用递归方法获得每一个数:,正序还是反序:先递归再输出?先输出再递归?,正序输出,反序输出,例,6.11,汉诺塔问题。有三根柱子,A,、,B,、,C,。设,A,柱上有,n,个盘子,盘子的大小不等,大的盘子在下,小的盘子在上,如下图所示。要求将,A,柱上的,n,个盘子移到,C,上,每一次只能移一个盘子。在移动过程中,可以借助于任一根柱子,但必须保证三根柱子上的盘子都是大的盘子在下,小的盘子在上。要求编一个程序打印出移动盘子的步骤。,6.6 作用域和存储类型,作用域,:,程序中说明的标识符,的,有效区,域,。分为:,块作用域(局部作用域),文件作用域(全局作用域),函数原型作用域,函数作用域,类作用域,:,后续章节介绍。,变量的存储类型,:,在变量说明时指定,,,决定何时为变量分配存储空间及该存储空间所具有的特征。,6.6.1作用域,块,:,用一对花括号,“,”,括起来的部分程序。,块作用域,:,在块内说明的标识符,,其作用域,始于标识符的说明处,,止,于块的结尾处。只能在该块内引用,。,1块作用域,局部变量,:,在函数内或在块,内,定义的变量。,局部变量的内存问题:程序执行到该块时,系统自动在栈内为局部变量分配内存,,在退出该块时,,系统自动回收该,块的局部变量,占用的内存,。,标识符同名:同一作用域不允许,不同作用域允许。,不同作用域的局部变量的同名问题解决方案:,内层标识符在其作用域内,将屏蔽其外层作用块的同名标识符。,(例6.12),for,语句中说明的变量具有块作用域,在,VC+,中,其作用域为包含,for,语句的那个内层块。,1块作用域,6.6.1作用域,在,for,语句中说明的变量具有块作用域。例如:,for(int,i=0;i10;i+),cout,i*it;,cout,i;,/VC+,允许,标准,C+,不允许,在,VC,中,这段程序等同于:,int,i;,for(i=0;i10;i+),cout,i*it;,cout,i;,2文件作用域,全局变量,(标识符):在函数外定义的变量(标识符)或用,extern,说明的变量(标识符)。,文件作用域:全局变量(标识符)的作用域。从定义位置开始到该源程序文件结束。,通过全局变量,增加了函数之间传递数据的途径,但过多使用会降低函数的独立性,。,局部变量与全局变量同名问题,(例6.14),规则1:,局部变量在其作用域内,将屏蔽与其同名的全局变量。,规则2:在同名局部变量作用域内,用作用域运算符可访问同名的全局变量。,3函数原型作用域,函数原型作用域:函数原型参数表中说明的标识符,其作用域,始于,说明处,,止于,函数原型说明的结束处。,4函数作用域,函数作用域:只有标号具有函数作用域,即在一个函数中定义的标号,在其整个函数内均可以引用。,同一函数内不允许标号同名,而在不同函数内允许标号同名。,不允许在一个函数内用,goto,语句转移到另一个函数内的某一个语句去执行。,6.6.2 存储类型,程序执行时,系统为它分配内存并将它装入内存。,程序占用内存分为:,程序区,:存放程序的可执行,代码,。,静态存储区,:存放程序中定义的,静态变量,。,动态存储区,:存放程序中定义的,动态变量,。,静态变量,:在程序开始执行时就为其分配内存的变量,直到程序执行结束时,才收回为变量分配的内存。静态变量的生命期为程序的执行期,即静态变量一直占用所分配的内存,不管是否处在它的作用域。,动态变量,:当程序执行到动态变量的作用域的开始处时,才为它分配内存;而执行到它的作用域的结束处时,收回为它分配的内存。该变量的生命期仅在变量的作用域内。,存储类型,:在变量说明时指定,决定何时为变量分配内存,何时收回分给变量的内存,反映了变量占用内存的期限。引入存储类型是为了提高内存使用效率。,为变量分配什么样的存储区,是由变量的存储类型所确定,而变量的存储类型由程序设计者根据程序设计的需要来指定。,变量的存储类型:,自动类型、寄存器类型、静态类型和外部类型。,6.6.2 存储类型,1自动类型变量,自动类型变量:在说明局部变量时,用,auto,修饰。由于,局部变量默认为自动类型变量,,因此在说明局部变量时,通常不用,auto,修饰。,举例:,void f(void),int,x;/,默认为:,auto,int,x;,auto,int,y;,自动类型变量为动态变量,,若,未赋初值,则其值不定,。如上面的变量,x,和,y,都没有确定的初值。,2静态类型变量,静态类型变量:用,static,修饰的变量,为静态变量。在说明静态类型变量时,,若没有指定初值,则编译器将其初值置为0,。,例如:,static float y=4.5f;/,静态全局变量,y,,初值4.5,static char s;/,静态全局变量,s,,初值0,void f(void),static,int,x;/,静态局部变量,x,,初值0,cout,x,y,s,endl,;,静态局部变量,:在程序开始执行时,获得所分配的内存,生存期是全程的,作用域是局部的。在调用函数而执行函数体后,系统并不收回这些变量占用的内存,当下次执行函数时,变量仍使用相同的内存,因此,这些变量仍保留原来的值。,静态局部变量的作用:保存函数运行后的结果,以便下次调用函数时,继续使用上次计算的结果。,(例6.15),静态全局变量,:作用域仅限于本程序文件内使用。若一个程序仅由一个文件组成,在说明全局变量时,有无,static,修饰,并无区别。,3.寄存器类型变量,寄存器类型变量:用,register,修饰的局部变量。,register,指示编译器为这类变量尽可能直接分配,CPU,中的寄存器,以提高存取速度。,例如:,register,int,i,j;,说明:,寄存器类型变量主要用作循环变量,存放临时值。,静态变量和全局变量不能定义为寄存器类型变量。,有的编译系统把寄存器变量作为自动变量来处理,有的编译系统限制了定义寄存器变量的个数。,4.外部类型变量,外部类型变量:在说明全局变量时,用,extern,修饰。,主要用于下列,两种情况:,同一文件中,全局变量使用在前,定义在后,例如:,多文件组成一个程序时,一个源程序文件中定义的全局变量要被其他若干个源程序文件引用时,例如:,/,c1.cpp,#include,float x;,extern float f();/,外部函数原型声明,void main(void),cout,f()n;,/c2.cpp,float f(),/,引用性说明外部变量,x,,使其,作用域扩至,f,函数,extern float x;,/问:这样声明有何优点?,return,x,+=2;,存储类型小结,基于变量访问的安全性以及内存利用效率等方面的考虑,,在实际编程时,优先使用自动变量,严格限制使用静态变量和外部变量,基本不用寄存器变量,。,不得不使用静态变量时,优先使用静态局部变量。,不得不使用全局变量时,优先使用静态全局变量。,不得不使用外部变量时,优先采用块作用域对外部变量的作用域做扩展。,以下程序的输出结果为:,#include,int,x=2;,void main(),int x,y=0;,x=+y+:x+;,coutxtyn;,:x=:x+x;,cout:xn;,#include,gcd(int,m,int,n),if(m,=n),return m;,else,if(m,n),return,gcd(m-n,n,);,else,return,gcd(m,n-m,);,void main(),cout gcd(114,36)endl;,cout,gcd(128,64),endl,;,分析以下程序的输出结果:,#include,void,swap(int,p1,int p2),int t=p1;,p1=p2;,p2=t;,void main(),int,a=2,b=3;,cout,a,b,endl,;,swap(a,b,);,cout,a,b,endl,;,分析以下程序的输出结果:,#include,using namespace std;,int,m=2;,int,func(int,a,int,b),static,int,i=2;,i+=m+1;m=,i+a+b,;,return m;,void main(),int,k=4,m=1,p;,p=,func(k,m,);,cout,pn;,p=,func(k,m,);,cout,p,endl,;,分析以下程序的输出结果:,#include,int,f(int,&,n,int,&m),static,int,k=10;,n+=m;k+=n;m+=k;,cout,k=k,endl,;,return(n+m,);,void,main(void,),int,a=3,b=4,k;,k=,f(a,b)+f(a,b,);,cout,k=kta=atb=b,endl,;,以下程序的输出结果是:,#include,void,trans(int,n),if(n,=16)trans(n/16);,if(n%16=10),cout,char(A+n%16-10);,else,cout,n%16;,void main(),trans(8);,cout,endl;trans(228);,6.7,C+,增加的函数特性,C+,对函数的声明、定义、调用方式和实现机制做了进一步完善和改进,增加了:,内联函数,带缺省参数值的函数,重载函数,函数模板:15.2节介绍。,6.7.1 内联函数,背景:函数调用时都会产生一些额外的时间开销,主要是系统栈的保护、参数的传递、系统栈的恢复等。对于那些函数体很小、执行时间很短但又频繁使用的函数来说,这种额外时间开销很可观。,内联函数机制:,不在调用时发生转移,而,在编译时将函数体嵌入到每个内联函数调用处,。这样就省去了参数传递、系统栈的保护与恢复等的时间开销。,内联函数的定义:,inline,(形参表),函数体,只有简单、频繁调用的函数才有必要说明为内联的。,内联函数的本质:,以增加程序代码的存储开销为代价来减少程序执行的时间开销。,内联函数说明:,内联函数一般不能含有循环语句和,switch,语句。,内联函数的定义必须出现在第一次被调用之前。,内联函数不能指定抛掷异常的类型。,函数用,inline,修饰只是向编译器提出了内联请求,,编译器是否作为内联函数来处理由编译器决定。,6.7.2 缺省参数值的函数,例6.17 具有缺省参数值的延时函数,#,include,void,delay(int,n=1000)for(;n0;n-);,void main(void),cout,延时1000个单位时间,n;,delay();,cout,延时800个单位时间,n;,delay(800);,使用具有缺省参数的函数时,应注意:,缺省参数的说明必须出现在函数调用之前,说明方法有两种:具有缺省参数值的函数的定义在函数调用之前说明,如,例6.17,所示。先给出函数的原型说明,并在原型说明中依次列出参数的缺省值,但在后面的函数定义中,不能再指定函数参数的缺省值,如,例6.18,所示。,参数的缺省值可以是表达式,,但应有确定的值。,函数的缺省参数可有多个,但缺省参数应从参数表的最右边依次向左设定。,如例6.18中,A,行不能写为:,float Area(float10,float);,同一函数在不同作用域,可用函数原型声明方式提供不同的缺省参数值。,6.7.3 函数的重载,函数重载:,两个或两个以上的函数同名,但形参的类型或形参的个数有所不同,。仅返回值不同,不能定义为重载函数。,函数重载的原则,:,只有功能相近的函数才有必要重载。互不相干的函数使用函数重载,只会造成混乱,降低程序的可读性。,函数重载的好处:,合理使用函数重载可以减轻用户对函数名的记忆负担,方便用户对函数的调用,提高程序的可读性。,(例6.19,),以下程序有没有错误?,#include,#define PI 3.1416,double,area(double,r=0)return PI*r*r;,double,area(double,a,double,b=0)return a*b;,void main(),cout,area(10),endl,;,cout,area(10,20),endl,;,
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 通信科技 > 开发语言

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服