1、1面向对象程序设计复习辅导(三)-函 数徐孝凯一个 C+语言程序由若干个程序文件和头文件所组成,每个头文件中通常带有用户类型的定义、符号常量的定义、函数的声明等内容,每个程序文件由若干个函数定义所组成,其中必有一个并且只有一个程序文件中包含有主函数 main,称此程序文件为主程序文件。函数是 C+程序中的基本功能模块和执行单元,这一章专门讨论函数的定义和调用,变量的作用域和生存期等内容。一、函数的定义(一)定义格式() 为系统或用户已定义的一种数据类型,它是函数执行过程中通过 return 语句要求返回的值的类型,又称为该函数的类型。当一个函数不需要通过 return 语句返回一个值时,称为无
2、返回值函数或无类型函数,此时需要使用保留字 void 作为类型名。当类型名为 int 时,可以省略不写,但为了清楚起见,还是写明为好。是用户为函数所起的名字,它是一个标识符,应符合 C+标识符的一般命名规则,用户通过使用这个函数名和实参表可以调用该函数。又称形式参数表,它包含有任意多个(含 0 个,即没有)参数说明项,当多于一个时其前后两个参数说明项之间必须用逗号分开。每个参数说明项由一种已定义的数据类型和一个变量标识符组成,该变量标识符成为该函数的形式参数,简称形参,形参前面给出的数据类型称为该形参的类型。一个函数定义中的可以被省略,表明该函数为无参函数,若用 void 取代,则也表明是无参
3、函数,若不为空,同时又不是保留字 void,则称为带参函数。是一条复合语句,它以左花括号开始,到右花括号结束,中间为一条或若干条 C+语句。在一个函数的参数表中,每个参数可以为任一种数据类型,包括普通类型、指针类型、数组类型、引用类型等,一个函数的返回值可以是除数组类型之外的任何类型,包括普通类型、指针类型和引用类型等。另外,当不需要返回值时,应把函数定义为 void 类型。(二) 定义格式举例(1) void f1() .(2) void f2(int x) .(3) int f3(int x,int* p) .(4) char* f4(char a).(5) int f5(intvoid
4、f10(const char* p, char key);在函数 f9 的函数体中只允许使用 x 和 y 的值,不允许修改它们的值。在函数 f10 的函3数体中只允许使用 p 所指向的字符对象或字符数组对象的值,不允许修改它们的值,但在函数体中既允许使用也允许修改形参 key 的值。3. 缺省参数在一个函数定义中,可根据需要对参数表末尾的一个或连续若干个参数给出缺省值,当调用这个函数时,若实参表中没有给出对应的实参,则形参将采用这个缺省值。如:void f11(int x, int y=0) .int f12(int a, char op=+, int k=10) .函数 f11 的定义带有两
5、个参数,分别为整型变量 x 和 y,并且 y 带有缺省值 0,若调用该函数的表达式为 f11(a,b),将把 a 的值赋给 x,把 b 的值赋给 y,接着执行函数体;若调用该函数的表达式为 f11(a+b),则也是正确的调用格式,它将把 a+b 的值赋给 x,因 y没有对应的实参,将采用缺省值 0,参数传送后接着执行函数体。函数 f12 的定义带有三个参数,其中后两个带有缺省值,所以调用它的函数格式有三种,一种只带一个实参,用于向形参 a 传送数据,后两个形参采用缺省值,第二种带有两个实参,用于分别向形参 a 和 op 传送数据,第三个形参采用缺省值,第三种带有三个实参,分别用于传送给三个形参
6、。若一个函数带有专门的函数原型语句,则形参的缺省值只能在该函数原型语句中给出,不允许在函数头中给出。如对于上述的 f11 和 f12 函数,其对应的函数原型语句分别为:void f11(int x, int y=0);int f12(int a, char op=+, int k=10);函数定义应分别改写为:void f11(int x, int y) .int f12(int a, char op, int k) .4. 数组参数在函数定义中的每个数组参数实际上是指向元素类型的指针参数。对于一维数组参数说明:它与下面的指针参数说明完全等价:*其中就是数组参数说明中的。如对于 f12 函数定
7、义中的数组参数说明 int a,等价于指针参数说明 int* a。也就是说,数组参数说明中的数组名 a 是一个类型为 int*的形参。注意:在变量定义语句中定义的数组,其数组名代表的是一个数组,它的值是指向第一个元素的指针常量,这与数组形参的含义有区别。对于二维数组参数说明:它与下面的指针参数说明完全等价:(*)如对于 f7 函数定义中的二维数组参数说明 float cN,等价于指针参数说明float(*c)N。5. 函数类型当调用一个函数时就执行一遍循环体,对于类型为非 void 的函数,函数体中至少必须带有一条 return 语句,并且每条 return 语句必须带有一个表达式,当执行到任
8、一条return 语句时,将计算出它的表达式的值,结束整个函数的调用过程,把这个值作为所求的函数值带回到调用位置,参与相应的运算;对于类型为 void 的函数,它不需要返回任何函数值,所以在函数体中既可以使用 return 语句,也可以不使用,对于使用的每条4return 语句不允许也不需要带有表达式,当执行到任一条 return 语句时,或执行到函数体最后结束位置时,将结束函数的调用过程,返回到调用位置向下继续执行。6. 内联函数当在一个函数的定义或声明前加上关键字 inline 则就把该函数声明为内联函数。计算机在执行一般函数的调用时,无论该函数多么简单或复杂,都要经过参数传递、执行函数体
9、和返回等操作。若把一个函数声明为内联函数后,在程序编译阶段系统就有可能把所有调用该函数的地方都直接替换为该函数的执行代码,由此省去函数调用时的参数传递和返回操作,从而加快整个程序的执行速度。通常可把一些相对简单的函数声明为内联函数,对于较复杂的函数则不应声明为内联函数。从用户的角度看,调用内联函数和一般函数没有任何区别。下面就是一个内联函数定义的例子,它返回形参值的立方。inline int cube(int n)return n*n*n;二、函数的调用(一)调用格式调用一个已定义或声明的函数需要给出相应的函数调用表达式,其格式为:()若调用的是一个无参函数,或全部形参为可选的函数,则被省略,
10、此时实参表为空。为一个或若干个用逗号分开的表达式,表达式的个数应至少等于不带缺省值的形参的个数,应不大于所有形参的个数,中每个表达式称为一个实参,每个实参的类型必须与相应的形参类型相同或兼容(即能够被自动转换为形参的类型,如整型与字符型就是兼容类型) 。每个实参是一个表达式,包括是一个常量、一个变量、一个函数调用表达式,或一个带运算符的一般表达式。如:(1) g1(25) /实参是一个整数(2) g2(x) /实参是一个变量(3) g3(a,2*b+3) /第一个为变量,第二个运算表达式(4) g4(sin(x),) /第一个为函数调用表达式,第二个为字符常量(5) g5( /作为单独的语句,
11、若有返回值则被丢失(2) y=f3(x,a); /返回值被赋给 y 保存(3) coutak) k=i;return ak;该函数的功能是从一维整型数组 an中求出具有最大值的元素并引用返回。当调用该函数时,其函数表达式既可以作为右值,从而取出 ak的值,又可以作为左值,从而向ak赋予新值。如:#includeintfor(int i=1;iak) k=i;return ak;void main()7int b8=25,37,18,69,54,73,62,31;coutint xk1(int n);void main()coutm;int sum=xk1(m)+xk1(2*m+1);cout8
12、void xk2(intvoid main()int x=12,y=18;coutvoid xk3(int* a, int* b);void xk4(intvoid main()int x=5,y=10;coutconst int N=8;int xk5(int a, int n);void main()int bN=1,7,2,6,4,5,3,-2;int m1=xk5(b,8);int m2=xk5(int m3=xk5(b+3,3);coutchar* xk6(char* sp, char* dp);void main()char a15=“abcadecaxybcw“;char b15
13、;char* c1=xk6(a,b);cout=i) dpi+=*p;/若 dp 数组的前 i 个元素均不等于*p,则把*p 写入 dpi元素中dpi=0; /写入字符串结束符return dp; xk6 函数的功能是把 sp 所指向的字符串,去掉重复字符后拷贝到 dp 所指向的字符数组中,并返回 dp 指针。在主函数中第一次调用 xk6 函数时,分别以 a 和 b 作为实参,第二次调用时分别以 a+4(即 a4的地址)和 b 作为实参。该程序运行后的输出结果为:abcdexyw abcadecaxybcw abcdexywdecaxybw abcadecaxybcw decaxybw程序 6:#includeint* xk7(int*int* xk7(int*a1=new int(2*a1+4);a2=new int(2*a2-1);cout“when leave xk7: *a1,*a2=“*a1“, “*a2endl;return a2;