《【教学课件】第4章函数.ppt》由会员分享,可在线阅读,更多相关《【教学课件】第4章函数.ppt(43页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、C+程序设计湖南大学 杜四春、银红霞 第4章 函数 4.1 函数概述 4.2 函数的定义与声明 4.3 函数的调用 C+程序设计湖南大学 杜四春、银红霞C+语言认为函数是一个能完成某一独立功能的子程序,也就是程序模块。函数就是对复杂问题的一种“自顶向下,逐步求精”思想的体现。编程者可以将一个大而复杂的程序分解为若干个相对独立而且功能单一的小块程序(函数)进行编写,并通过在各个函数之间进行调用,来实现总体的功能。C+程序设计湖南大学 杜四春、银红霞4.1 函数概述 使用函数的优点:(1)可读性好;(2)易于查错和修改;(3)便于分工编写,分阶段调试;(4)各个函数之间接口清晰,便于相互间交换信息
2、和使用;(5)节省程序代码和存储空间;(6)减少用户总的工作量;(7)成为实现结构程序设计思想的重要工具;(8)扩充语言和计算机的原设计能力;(9)便于验证程序正确性。C+程序设计湖南大学 杜四春、银红霞设计C+程序的过程,实际上就是编写函数的过程,至少也要编写一个main()函数。执行C+程序,也就是执行相应的main()函数。即从main()函数的第一个左花括号“”开始,依次执行后面的语句,直到最后一个右花括号“”为止。如果在执行过程中遇到其他的函数,则调用其他函数。调用完后,返回到刚才调用函数的下一条语句继续执行。而其他函数也只有在执行main()函数的过程中被调用时才会执行。C+程序设
3、计湖南大学 杜四春、银红霞函数可以被一个函数调用,也可以调用另一个函数,它们之间可以存在着调用上的嵌套关系。但是,C+不允许函数的定义嵌套,即在函数定义中再定义一个函数是非法的。C+函数是一个独立完成某个功能的语句块,函数与函数之间通过输入和输出来联系。C+程序设计湖南大学 杜四春、银红霞4.2 函数的定义与声明在C+程序中调用函数之前,首先要对函数进行定义。如果调用此函数在前,函数定义在后,就会产生编译错误。为了使函数的调用不受函数定义位置的影响,可以在调用函数前进行函数的声明。这样,不管函数是在哪里定义的,只要在调用前进行函数的声明,就可以保证函数调用的合法性。C+程序设计湖南大学 杜四春
4、、银红霞4.2.1 函数的定义函数的定义 C+中的每一个函数都是从四个方面来进行定义:类型、函数名、形式参数表、函数体。定义一个函数的语法格式为:类型 函数名(形式参数表)函数体;C+程序设计湖南大学 杜四春、银红霞例如:intmax(inta,intb)intt;if(ab)t=a;elset=b;returnt;C+程序设计湖南大学 杜四春、银红霞类型就是该函数的类型,也就是该函数的返回值的类型,此类型可以是C+中除函数、数组类型之外的任何一个合法的数据类型,包括普通类型、指针类型和引用类型等。函数的返回值通常指明了该函数处理的结果,由函数体中的return语句给出。一个函数可以有返回值,
5、也可以无返回值(称为无返回值函数或无类型函数)。此时需要使用保留字void作为类型名,而且函数体中也不需要再写return语句,或者return的后面什么也没有。每个函数都有类型,如果在函数定义时没有明确指定类型,则默认类型为int。C+程序设计湖南大学 杜四春、银红霞函数名是一个有效的C+标识符,遵循一般的命名规则。在函数名后面必须跟一对小括号“()”,用来将函数名与变量名或其他用户自定义的标识符区分开来。在小括号中可以没有任何信息,也可以包含形式参数表。C+程序通过使用这个函数名和实参表可以调用该函数。主函数的名称规定取编译器默认的名称main()。C+程序设计湖南大学 杜四春、银红霞形式
6、参数表又称参数表,写在函数名后面的一对圆括号内。它可包含任意多个(含0个,即没有)参数说明项,当多于一个时其前后两个参数说明项之间必须用逗号分开。每个参数说明项由一种已定义的数据类型和一个变量标识符组成,该变量标识符称为该函数的形式参数,简称形参,形参前面给出的数据类型称为该形参的类型。每个形参的类型可以为任一种数据类型,包括普通类型、指针类型、数组类型、引用类型等。一个函数定义中的可以被省略,表明该函数为无参函数,若用void取代,则也表明是无参函数,若不为空,同时又不是保留字void,则称为带参函数。C+程序设计湖南大学 杜四春、银红霞是一条复合语句,它以左花括号开始,到右花括号结束,中间
7、为一条或若干条C+语句,用于实现函数执行的功能。注意:在一个函数体内允许有一个或多个return语句,一旦执行到其中某一个return语句时,return后面的语句就不再执行,直接返回调用位置继续向下执行。C+程序设计湖南大学 杜四春、银红霞函数形参也可以在函数体外说明。如下例:func1(inta,intb)也可写成:func1(a,b)inta;intb;C+程序设计湖南大学 杜四春、银红霞#includeiostream.hintfunc(intn)if(n0)return1;elseif(n=0)return0;elsereturn-1;voidmain()intn;coutPleas
8、einputn:n;coutntheresult:func(n)endl;例4-1:给出以下程序的运行结果。C+程序设计湖南大学 杜四春、银红霞此程序的运行结果为:Pleaseinputn:2theresult:1Pleaseinputn:-2theresult:-1C+程序设计湖南大学 杜四春、银红霞请注意:C+中不允许函数定义嵌套,即在函数定义中再定义一个函数是非法的。一个函数只能定义在别的函数的外部,函数定义之间都是平行的,互相独立的。例如:下面的代码在主函数中非法嵌套了一个f()函数定义:voidmain()voidf()/C+程序设计湖南大学 杜四春、银红霞4.2.2 函数的声明函数
9、的声明函数声明也称函数模型(或函数原型)。在主调函数中,如果要调用另一个函数,则须在本函数或本文件中的开头将要被调用的函数事先作一声明。声明函数,就是告诉编译器函数的返回类型、名称和形参表构成,以便编译系统对函数的调用进行检查。函数声明的一般格式为:函数类型 函数名(形式参数表);除了需在函数声明的末尾加上一个分号“;”之外,其他的内容与函数定义中的第一行(称函数头)的内容一样。C+程序设计湖南大学 杜四春、银红霞例如:设有一函数的定义为:doublefunc1(doublea,intb,floatc)函数体正确完整的函数声明应为:doublefunc1(doublex,inty,floatz
10、);/末尾要加上分号C+程序设计湖南大学 杜四春、银红霞也可以写为如下形式:doublefunc1(double,int,float);/函数声明中省略了形参名或写为如下形式:doublefunc1(doublea,intb,floatc);/函数声明中的形参名与/函数定义中的形参名不同C+程序设计湖南大学 杜四春、银红霞不能写为如下形式:doublefunc1(x,y,z);/函数声明中省略了形参类型或:func1(doublex,inty,floatz);/函数声明中省略了函数类型或:doublefunc1(inty,floatz,doublex);/函数声明中形参顺序调换了C+程序设计湖
11、南大学 杜四春、银红霞4.3 函数的调用 4.3.1 函数调用的格式:函数调用的格式:在C+中,除了主函数main由系统自动调用外,其他函数都是由主函数直接或间接调用的。函数调用的语法格式为:函数名(实际参数表);实参应该与函数定义中的形参表中的形参一一对应,即个数相等、次序一致且对应参数的数据类型相同或相容。每个实参是一个表达式,并且必须有确定的值。C+程序设计湖南大学 杜四春、银红霞如:g1(25)/实参是一个整数g2(x)/实参是一个变量g3(a,2*b+3)/第一个为变量,第二个运算表/达式g4(sin(x),)/第一个为函数调用表达式,第二/个为字符常量g5(&d,*p,x/y-1)
12、/分别为取地址运算、间接访问和/一般运算表达式 C+程序设计湖南大学 杜四春、银红霞常见的函数调用方式有下列两种:n方式一:将函数调用作为一条表达式语句使用,只要求函数完成一定的操作,而不使用其返回值。若函数调用带有返回值,则这个值将会自动丢失。例如:max(3,5);n方式二:对于具有返回值的函数来说,把函数调用语句看作语句一部分,使用函数的返回值参与相应的运算或执行相应的操作。例如:inta=max(3,5);inta=max(3,5)+1;coutmax(3,5)endl;if(f1(a,b)cout”true”endl;inta=2;a=max(max(a,3),5);C+程序设计湖南
13、大学 杜四春、银红霞#includeintmax(inta,intb,intc)intt;t=a;if(bt)t=b;if(ct)t=c;returnt;voidmain()intx,y,z;cout”Pleaseinputxyz:”xyz;intm=max(x,y,z);cout”Themaxis:”mendl;例:函数调用。C+程序设计湖南大学 杜四春、银红霞4.3.2 函数调用的过程函数调用的过程当调用一个函数时,整个调用过程分为三步进行,第一步是参数传递,第二步是函数体执行,第三步是返回,即返回到函数调用表达式的位置。C+程序设计湖南大学 杜四春、银红霞4.3.3 函数调用时的参数传递
14、函数调用时的参数传递参数传递称为“实虚结合”,即实参向形参传递信息,使形参具有确切地含义(即具有对应的存储空间和初值)。这种传递又分为两种不同的方式,一种是按值传递,另一种是地址传递或引用传递。C+程序设计湖南大学 杜四春、银红霞1.按按值传递以按值传递方式进行参数传递的过程为:首先计算出实参表达式的值,接着给对应的形参变量分配一个存储空间,该空间的大小等于该形参类型的长度,然后把已求出的实参表达式的值一一存入到为形参变量分配的存储空间中,成为形参变量的初值,供被调用函数执行时使用。这种传递是把实参表达式的值传送给对应的形参变量,故称这种传递方式为“按值传递”。这种方式被调用函数本身不对实参进
15、行操作,也就是说,即使形参的值在函数中发生了变化,实参的值也完全不会受到影响,仍为调用前的值。C+程序设计湖南大学 杜四春、银红霞#includeiostream.hvoidswap(int,int);voidmain()inta=3,b=4;couta=a,b=“bendl;swap(a,b);couta=a,b=bendl;voidswap(intx,inty)intt=x;x=y;y=t;此程序的运行结果为:a=3,b=4a=3,b=4例4-3:按值传递。C+程序设计湖南大学 杜四春、银红霞2.地址地址传递如果在函数定义时将形参的类型说明成指针,对这样的函数进行调用时就需要指定地址值形式
16、的实参。这时的参数传递方式即为地址传递方式。这种地址传递与上述的按值传递不同,它把实参的存储地址传送给对应的形参,从而使得形参指针和实参指针指向同一个地址。因此,被调用函数中对形参指针所指向的地址中内容的任何改变都会影响到实参。C+程序设计湖南大学 杜四春、银红霞#includeiostream.hvoidswap(int*,int*);voidmain()inta=3,b=4;couta=a,b=“bendl;swap(&a,&b);couta=a,b=“bendl;voidswap(int*x,int*y)intt=*x;*x=*y;*y=t;此程序的运行结果为:a=3,b=4a=4,b=
17、3例4-4:地址传递。C+程序设计湖南大学 杜四春、银红霞3.引用引用传递按值传递方式容易理解,但形参值的改变不能对实参产生影响;地址传递方式虽然可以使得形参的改变对相应的实参有效,但如果在函数中反复利用指针进行间接访问,会使程序容易产生错误且难以阅读。如果以引用作为参数,则既可以使得对形参的任何操作都能改变相应的实参的数据,又使函数调用显得方便、自然。引用传递方式是在函数定义时在形参前面加上引用运算符“&”。C+程序设计湖南大学 杜四春、银红霞#includeiostream.hvoidswap(int&,int&);voidmain()inta=3,b=4;couta=a,b=“bendl
18、;swap(a,b);couta=a,b=“bendl;voidswap(int&x,int&y)intt=x;x=y;y=t;此程序的运行结果为:a=3,b=4a=4,b=3例4-5:引用传递。C+程序设计湖南大学 杜四春、银红霞4.3.4 内联函数内联函数内联扩展(inline expansion)简称为内联(inline),内联函数也称为内嵌函数。当在一个函数的定义或声明前加上关键字inline则就把该函数定义为内联函数,它主要是解决程序的运行效率。计算机在执行一般函数的调用时,无论该函数多么简单或复杂,都要经过参数传递、执行函数体和返回等操作,这些操作都需要一定的时间开销。若把一个函数
19、定义为内联函数后,在程序编译阶段,编译器就会把每次调用该函数的地方都直接替换为该函数体中的代码,由此省去函数的调用及相应的保存现场、参数传递和返回操作,从而加快整个程序的执行速度。C+程序设计湖南大学 杜四春、银红霞例4-6:#includeiostream.hinlineintabs(intx)returnx0?-x:x;voidmain()inta,b=3,c,d=-4;a=abs(b);c=abs(d);couta=a,c=cendl;此程序的运行结果为:a=3,c=4C+程序设计湖南大学 杜四春、银红霞内联函数可以在一开始仅定义或声明一次,但必须在函数被调用之前定义或声明。否则,如下例
20、,编译器不认为那是内联函数,仍然如同对普通函数那样处理该函数的调用过程 从用户的角度看,调用内联函数和一般函数没有任何区别。请注意:内联函数的函数体有一些限制:内联函数中不能含有任何循环以及switch和goto语句;内联函数中不能说明数组;递归函数(自己调用自己的函数)不能定义为内联函数。C+程序设计湖南大学 杜四春、银红霞4.3.5 重载函数重载函数函数重载又称为函数的多态性,是指同一个函数名对应着多个不同的函数。所谓“不同”是指这些函数的形参表必须互不相同,或者是形参的个数不同,或者是形参的类型不同,或者是两者都不相同,否则将无法实现函数重载。例如,下面是合法的重载函数:intfunc1
21、(int,int);intfunc1(int);doublefunc1(int,long);doublefunc1(long);C+程序设计湖南大学 杜四春、银红霞重载函数的类型,即函数的返回类型可以相同,也可以不同。但如果仅仅是返回类型不同而函数名相同、形参表也相同,则是不合法的,编译器会报“语法错误”。如:intfunc1(inta,intb);doublefunc1(inta,intb);除形参名外都相同的情况,编译器不认为是重载函数,只认为是对同一个函数原型的多次声明。在调用一个重载函数func1()时,编译器必须判断函数名func1到底是指哪个函数。它是通过编译器,根据实参的个数和类
22、型对所有func1()函数的形参一一进行比较,从而调用一个最匹配的函数。C+程序设计湖南大学 杜四春、银红霞4.3.6 带默认形参值的函数带默认形参值的函数在C+语言中调用函数时,通常要为函数的每个形参给定对应的实参。若没有给出实参,则按指定的默认值进行工作。当一个函数既有定义又有声明时,形参的默认值必须在声明中指定,而不能放在定义中指定。只有当函数没有声明时,才可以在函数定义中指定形参的默认值。C+程序设计湖南大学 杜四春、银红霞默认值的定义必须遵守从右到左的顺序,如果某个形参没有默认值,则它左边的参数就不能有默认值。如:voidfunc1(inta,doubleb=4.5,intc=3);
23、/合法voidfunc1(inta=1,doubleb,intc=3);/不合法 在进行函数调用时,实参与形参按从左到右的顺序进行匹配,当实参的数目少于形参时,如果对应位置形参又没有设定默认值,就会产生编译错误;如果设定了默认值,编译器将为那些没有对应实参的形参取默认值。C+程序设计湖南大学 杜四春、银红霞 注意:形参的默认值可以是全局常量、全局变量、表达式、函数调用,但不能为局部变量。例如,下例不合法:voidfunc1()intk;voidg(intx=k);/k为局部变量 C+程序设计湖南大学 杜四春、银红霞4.3.7 函数的嵌套调用函数的嵌套调用由前述可知,C+函数不能嵌套定义,即一个
24、函数不能在另一个函数体中进行定义。但在使用时,允许嵌套调用,即在调用一个函数的过程中又调用另一个函数。例如:func1(inta,floatb)floatc;c=func2(b-1,b+1);intfunc2(floatx,floaty)函数体func1和func2是分别独立定义的函数,互不从属。C+程序设计湖南大学 杜四春、银红霞4.3.8 函数的递归调用函数的递归调用一个函数直接或间接地调用自身,这种现象就是函数的递归调用。递归调用有两种方式:直接递归调用和间接递归调用。直接递归调用即在一个函数中调用自身,间接递归调用即在一个函数中调用了其他函数,而在该其他函数中又调用了本函数。利用函数的
25、递归调用,可将一个复杂问题分解为一个相对简单且可直接求解的子问题(“递推”阶段);然后将这个子问题的结果逐层进行回代求值,最终求得原来复杂问题的解(“回归”阶段)。C+程序设计湖南大学 杜四春、银红霞#includeiostream.hlongf(intn)if(n0)cout“error!“endl;return(-1);elseif(n=1)return(1);elsereturn(n*f(n-1);voidmain()longf(intn);intn;coutpleaseinputn:“n;coutn!=f(n)endl;此程序的运行结果为:pleaseinputn:5n!=120例4-12:求n的阶乘。(函数递归调用的例程。)