1、1,2.5 函 数,函数的声明和调用 函数间的参数传递 内联函数 带默认形参值的函数 函数重载 C+系统函数,2,一、函数的声明和调用,1、函数的声明 函数是面向对象程序设计中,对功能的抽象 函数声明的语法形式 类型标识符 函数名(形式参数表) 语句序列 ,/ 若无返回值,写void,3,形式参数表name1, name2, ., namen 函数的返回值 由 return 语句给出,例如: return 0; 无返回值的函数(void类型),不必写return语句。,4,2、函数的调用,调用前先声明函数原型: 在调用函数中,或程序文件中所有函数之外,按如下形式说明:类型标识符 被调用函数名(
2、含类型说明的形参表); 调用形式 函数名(实参列表); 嵌套调用 函数可以嵌套调用,但不允许嵌套定义。 递归调用,5,例1:编写一个求x的n次方的函数,#include using namespace std; double power(double x, int n); int main() cout“5 to the power 2 is “ power(5,2)endl; double power(double x, int n) double val=1.0;while (n-) val=val*x;return(val); /运行结果:5 to the power 2 is 25,6
3、,例2:数制转换,题目:输入一个8位二进制数,将其转换为十进制数输出。 例如:11012=1(23)+1(22)+0(21)+1(20)=1310 所以,如果输入1101,则应输出13,#include using namespace std; double power (double x, int n); int main() int i;int value = 0;char ch;cout = 0; i-)cin ch;if (ch = 1)value += int(power(2,i);cout “Decimal value is “valueendl; double power (do
4、uble x, int n) double val = 1.0;while (n-) val *= x;return(val); ,运行结果: Enter an 8 bit binary number 01101001 Decimal value is 105,7,8,例3:编写程序求的值,其中arctan用如下形式的级数计算:直到级数某项绝对值不大于10-15为止;和x均为double型。,#include using namespace std; double arctan(double x); void main() double a,b;double arctan(double x);
5、/函数原型声明a=16.0*arctan(1/5.0); b=4.0*arctan(1/239.0); /注意:因为整数相除结果取整,/如果参数写1/5,1/239,结果就都是0cout“PI=“a-bendl; ,9,double arctan(double x) int i;double r,e,f,sqr;sqr=x*x;r=0; e=x; i=1;while(e/i1e-15)f=e/i;r=(i%4=1)? r+f : r-f;e=e*sqr; i+=2;return r; ,运行结果: PI=3.14159,10,11,3、函数调用的执行过程,12,4、嵌套调用,main调fun1
6、()结束,fun1()调fun2()返回,fun2()返回,13,例4: 输入两个整数,求平方和。,#include using namespace std; int fun1(int x,int y); int main() int a,b;int fun1(int x,int y);cinab;cout“a、b的平方和:“ fun1(a,b)endl; ,int fun1(int x,int y) int fun2(int m);return (fun2(x)+fun2(y); int fun2(int m) return (m*m); 运行结果: 3 4 a、b的平方和:25,14,15
7、,5、递归调用,函数直接或间接地调用自身,称为递归调用。 递归过程的两个阶段: 递推:4!=43!3!=32!2!=21!1!=10!0!=1 未知 已知 回归: 4!=43!=243!=32!=62!=21!=21!=10!=10!=1 未知 已知,16,例5:求n!,分析:计算n!的公式如下:这是一个递归形式的公式,应该用递归函数实现。,源程序: #include using namespace std; long fac(int n) long f;if (n0) cout“n0,data error!“endl;else if (n=0) f=1;else f=fac(n-1)*n;r
8、eturn(f); ,17,int main() long fac(int n);int n;long y;coutn;y=fac(n);coutn“!=“yendl; 运行结果: Enter a positive integer:8 8!=40320,18,19,课堂作业:汉诺塔问题,有三根针A、B、C。A针上有N个盘子,大的在下,小的在上,要求把这N个盘子从A针移到C针,在移动过程中可以借助B针,每次只允许移动一个盘,且在移动过程中在三根针上都保持大盘在下,小盘在上。,分析: 将n 个盘子从A针移到C针可以分解为下面三个步骤: 将A 上n-1个盘子移到 B针上(借助C针); 把A针上剩下的
9、一个盘子移到C针上; 将n-1个盘子从B针移到C针上(借助A针); 事实上,上面三个步骤包含两种操作: 将多个盘子从一个针移到另一个针上,这是一个递归的过程。 hanoi函数实现。 将1个盘子从一个针上移到另一针上。 用move函数实现。,20,#include using namespace std; void move(char getone,char putone) cout“putoneendl; void hanoi(int n,char one,char two,char three) void move(char getone,char putone);if (n=1) move
10、 (one,three);else hanoi(n-1,one,three,two);move(one,three);hanoi(n-1,two,one,three); ,21,int main() void hanoi(int n,char one,char two,char three);int m;coutm;cout“the steps to moving “m“ diskes:“endl;hanoi(m,A,B,C); ,22,运行结果: Enter the number of diskes:3 the steps to moving 3 diskes: AC AB CB AC BA
11、 BC AC,23,24,二、函数的参数传递机制,1、传递参数值 在函数被调用时才分配形参的存储单元。 实参可以是常量、变量或表达式。 实参类型必须与形参相符。 传递时是传递参数值,即单向传递。,25,26,例6 输入两个整数交换后输出,#include using namespace std; void Swap(int a, int b); void main() int x=5, y=10;cout“x=“x“ y=“yendl;Swap(x,y);cout“x=“x“ y=“yendl;,void Swap(int a, int b) int t;t=a;a=b;b=t; 运行结果:x
12、=5 y=10x=10 y=5,27,29,2、用引用做形参,引用( 声明一个引用时,必须同时对它进行初始化,使它指向一个已存在的对象(变量或常量)。 一旦一个引用被初始化后,就不能改为指向其它对象。 引用可以作为形参 void swap(int &a, int &b) .,30,例7 输入两个整数交换后输出,#include using namespace std; void Swap(int ,运行结果: x=5 y=10 x=10 y=5,Swap(x,y);,31,32,三、内联函数声明与使用,声明时使用关键字 inline。 编译时在调用处用函数体进行替换,节省了参数传递、控制转移等
13、开销。 注意: 内联函数体内不能有循环语句和switch语句。 内联函数的声明必须出现在内联函数第一次被调用之前。 对内联函数不能进行异常接口声明。,33,例8 内联函数应用举例,#include using namespace std; inline double CalArea(double radius) return 3.14*radius*radius; int main() double r(3.0);double area;area=CalArea(r);coutareaendl;return 0; ,34,四、带默认形参值的函数,1、默认形参值的作用: 函数在声明时可以预先给出
14、默认的形参值,调用时如给出实参,则采用实参值,否则采用预先给出的默认形参值。 例如: int add(int x=5,int y=6) return x+y; int main() add(10,20);/10+20add(10); /10+6add(); /5+6 ,35,2、默认形参值的说明次序,默认形参值必须从右向左顺序声明,并且在默认形参值的右面不能有非默认形参值的参数。因为调用时实参取代形参是从左向右的顺序,且不可有“间断点”。 例: int add(int x,int y=5,int z=6);/正确 int add(int x=1,int y=5,int z);/错误 int a
15、dd(int x=1,int y,int z=6);/错误,36,3、默认形参值与函数的调用位置,调用出现在函数体实现之前时,默认形参值必须在函数原形中给出。 例:,int add(int x=5,int y=6); int main() add(); /调用在实现前 int add(int x,int y) return x+y; ,int add(int x=5,int y=6) return x+y; int main() add(); /调用在实现后 ,37,4、默认形参值的作用域,在相同的作用域内,默认形参值的说明应保持惟一,但如果在不同的作用域内,允许说明不同的默认形参。 例: i
16、nt add(int x=1,int y=2); int main() int add(int x=3,int y=4);add();/使用局部默认形参值(实现3+4) void fun() .add();/使用全局默认形参值(实现1+2) ,38,五、重载函数的声明,C+允许功能相近的函数在相同的作用域内以相同函数名声明,从而形成重载。方便使用,便于记忆。 例:,39,注意事项,不要将不同功能的函数声明为重载函数,以免出现调用结果的误解、混淆。这样不好:,重载函数的形参必须不同:个数不同或类型不同。 编译程序将根据实参和形参的类型及个数的最佳匹配来选择调用哪一个函数。,40,例9 重载函数应
17、用举例,编写三个名为add的重载函数,分别实现两整数相加、两实数相加和两个复数相加的功能。#include using namespace std; struct complex double real;double imaginary; ;,int main() int m, n;double x, y;complex c1, c2, c3;int add(int m, int n);double add(double x, double y);complex add(complex c1, complex c2);coutmn;cout“integer m+n“=“add(m,n)endl
18、;,41,coutxy;coutc1.realc1.imaginary;coutc2.realc2.imaginary;c3=add(c1,c2);cout“complex number (“c1.real,c1.imaginary “)+(“c2.real,c2.imaginary“)=(“c3.real,c3.imaginary“)n“; ,42,int add(int m, int n) return m+n; double add(double x, double y) return x+y; complex add(complex c1, complex c2) complex c;
19、c.real=c1.real+c2.real;c.imaginary=c1.imaginary+c2.imaginary;return c; ,43,运行结果: Enter two integer: 3 5 integer 3+5=8 Enter two real number: 2.3 5.8 real number 2.3+5.8= 8.1 Enter the first complex number: 12.3 45.6 Enter the second complex number: 56.7 67.8 complex number (12.3,45.6)+(56.7,67.8)= (
20、69,113.4),44,45,六、C+系统函数,C+的系统库中提供了几百个函数可供程序员使用。 例如:求平方根函数(sprt)、求绝对值函数(abs)等。 使用系统函数时要包含相应的头文件。 例如:math.h 或 cmath,46,例10 系统函数应用举例,题目: 从键盘输入一个角度值,求出该角度的正弦值、余弦值和正切值。 分析: 系统函数中提供了求正弦值、余弦值和正切值的函数:sin()、cos()、tan(),函数的说明在头文件math.h和cmath中。,#include #include using namespace std; const double pi(3.14159265
21、); int main() double a,b;cina;b=a*pi/180;cout“sin(“a“)=“sin(b)endl;cout“cos(“a“)=“cos(b)endl;cout“tan(“a“)=“tan(b)endl; ,运行结果: 30 sin(30)=0.5 cos(30)=0.866025 tan(30)=0.57735,47,48,查找系统函数的使用说明,查编译系统的库函数手册 查工具软件的help系统,49,补充说明,Const修饰符define PI 3.14159;const int PI = 3.14159; 优点:安全性高(有自己明确的数据类型,编译时可以
22、进行严格的类型检查),50,const 修饰符的安全性,1、指向常量的指针const int *LENGTH = 7; 2、常指针int * const LENGTH = 7; 3、将函数参数声明为常类型void write( const char *greeting);,51,函数原型C要求为每一个函数建立原型,目的是让编译程序检查函数调用是否合法。养成良好的编程风格 1、参数表中可以只有参数类型:float area( float );float area( float r );,52,2、参数说明必须放在括号中int max( int a, int b ) return (a =b)?a
23、:b; /* int max(a, b) int a, b; / error ! return (a =b)?a:b; */,53,3、参数表若为空则说明该函数没有参数void func1();void func2(void);在C语言中上一行的函数可以带多个参数,54,课堂练习,1、编写一个完整的C程序,实现: 求均匀圆柱体的质量,其中密度默认为1.0,横截面面积默认为0.01 2、编写一个完整的C程序,实现:求两个整数的最大值;求3个整数的最大值。 (引用作为函数形参、函数重载、形参带默认值),55,求质量,#include #include using namespace std; do
24、uble mass( double h, double s=0.01, double p=1.0 ) return h * s * p; int main() coutabc;coutmass(a, b, c); ,56,求最大值,#include using namespace std; int max( int a, int b ); int max( int a, int b, int c ); int main() int x, y, z;coutxy;,57,coutxyz; cout“the biggest is:”max(x,y,z); ,58,int max( int a, int b ) if( a=b ) return a;else return b; ,59,int max( int a, int b, int c ) int temp;temp = (a=b)? a : b;temp = (c=temp)? c : temp;return temp;,60,int max( int a, int b, int c ) return max( a, max( b, c ) );,