1、第4章 函数,4.1 函数的定义和使用 4.2 函数的参数传递 4.3 函数的嵌套调用 4.4 函数的递归调用 4.5 内联函数 4.6 函数重载 4.7 带默认形参值的函数 4.8 函数的存储类别,4.1 函数的定义与使用,系统库函数:需要包含相应的头文件,如 #include 系统所提供的库函数都是完成一些通用功能的函数,在实际的程序设计中,自己还需要编写大量完成特殊功能的函数,我们称之为用户自定义函数。 4.1.1 函数的定义函数定义的一般格式为: 函数类型 函数名( 形式参数表) 语句组 ,第4章 函数,例4.1 求两个整数中较大的值的函数,#include int max(int x
2、, int y); void main() int a,b,c;cout a b;c = max(a,b);cout y) m=x;else m=y;return m; ,程序运行结果为: 请输入两个整数,用空格分隔:20 30 a,b中较大的数是:30,第4章 函数,函数调用语句,主调函数,被调函数,4.1 函数的定义与使用,4.1.1 函数的定义(续一)1. 函数类型与返回值函数的类型就是函数返回值的类型,可以是C+中的任何数据类型。函数的返回值由函数体中的return语句给出。return语句的一般格式为:return (表达式);或 return 表达式;或 return ;函数的类型
3、要与return语句的返回值类型相同。若不一致则以函数类型为准,将返回值类型转换为函数类型,若不能转换,则编译过程会出错! 若函数不需要返回值,则应将类型指定为void。,第4章 函数,执行该语句时,不带回返回值,只是返回主调函数,4.1 函数的定义与使用,4.1.1 函数的定义(续二)2. 函数的参数函数通过参数接收数据。函数头中的参数为形式参数(或形参),在函数调用时给出的参数称为实际参数(或实参)。实参必须是一个实际的值,而形参只有在发生实际调用时才有具体的值。如果不需要为函数提供数据,则可以没有参数,称之为无参函数。,第4章 函数,4.1 函数的定义与使用,4.1.2 函数的声明与调用
4、函数调用的一般格式:函数名(实际参数表)注意:若无形参,也不必给出实参,但括号不能省略。实参与形参个数应一致,类型要一一对应。函数原型声明:在调用函数前,对函数进行说明。通常用于函数定义出现在函数调用之后的情况。函数原型声明的一般格式: 函数类型 函数名(形式参数表);注意:函数原型中可以不写出参数名。如:double power(double, int);,第4章 函数,例4.2 编写一个求x的n次方的函数,#include double power(double x, int n); void main() double x;int n;cout x n;cout x “的“ n “次方是
5、:“ power(x,n) endl; double power(double x, int n) double a = 1.0;int i;for(i=1; i=n; i+) a *= x;return a; ,程序运行结果为: 请输入X和N的值,用空格分隔:3.0 4 3的4次方是:81,第4章 函数,4.2 函数的参数传递,根据函数的功能,函数的形参可以选择为数值、引用或指针三种形式。 4.2.1 值传递C+中参数的传递是单向的,即只能将实参的值传递给形参,而形参值的改变对实参没有影响。 例4.3 写一个函数交换主函数中两个变量的值考虑:使用值传递,将需要交换的变量作为实参传递给函数的形
6、参,在函数体中完成交换值的过程,这种做法能否实现程序要求?,第4章 函数,例4.3 源程序,#include void swap(int x, int y); void main() int a, b; a = 10; b = 20; swap(a, b); cout a “, “ b endl; ,程序运行结果为: 10,20,void swap(int x, int y) int temp; temp = x; x = y; y = temp; ,第4章 函数,注意:值传递时,函数的实参与形参在内存中占用不同的存储空间,值只能由实参传递给形参,而形参的变化并不会影响实参。因此不能完成程序功
7、能。,4.2 函数的参数传递,4.2.2 使用引用1. 引用的概念引用是一种特殊的变量,可以认为是一个变量的别名。 定义引用的一般格式:类型说明符 首先定义变量a,并初始化为1,然后定义引用b,并初始化为a,即b是a的别名,因此a和b是同一个单元。 注意:定义引用时一定要初始化,指明该引用变量是谁的别名。,第4章 函数,例4.4 引用的使用,#include void main() int a=1; int c=10; int ,程序运行结果: 1,1,10 10,10,10 20,20,10,定义引用b,并将其作为a的别名,第4章 函数,将c的值赋给b,不是将b作为c的别名,4.2 函数的参
8、数传递,4.2.2 使用引用(续一)2. 引用作为函数的参数例4.5 写一个函数,用引用作为参数,交换函数中两个变量的值。,第4章 函数,#include void swap(int x, int y); void main() int a, b; a = 10; b = 20; swap(a, b); cout a “, “ b endl; ,void swap(int ,程序运行结果为: 20,10,4.2 函数的参数传递,4.2.2 使用引用(续二)例4.5程序运行过程中参数值的变化图示,第4章 函数,注意:引用作参数时,函数的实参与形参在内存中共用存储单元,因此形参的变化会使实参同时变
9、化。,4.3 函数的嵌套调用,函数的嵌套调用是指,在执行被调用函数时,被调用函数又调用了其它函数。 嵌套调用的执行过程:,第4章 函数,例4.6 求1! + 2! + n!,#include long f1(int n); long f2(int m); void main() int n; long s; cout n; s = f1(n); cout s endl; ,第4章 函数,long f1(int n) / 求1!+2!+n! int i; long sum = 0; for(i=1; i=n; i+)sum += f2(i); return sum; long f2(int m)
10、 / 求m! int i; long s = 1; for(i=1; i=m; i+)s *= i; return s; ,程序运行结果: 请输入n的值:5 153,例4.7 输入两个整数,求平方和,#include int fun2(int m); int fun1(int x,int y); void main(void) int a,b;cout a b;cout “a、b的平方和:“ fun1(a,b) endl; int fun1(int x, int y) return ( fun2(x) + fun2(y) ); int fun2(int m) return ( m*m ); ,
11、第4章 函数,程序运行结果: 请输入两个整数:4 5 a、b的平方和:41,4.4 函数的递归调用,一个函数在它的函数体内,直接或间接地调用它自身,称为递归调用。这种函数称为递归函数。 直接或间接调用函数自身的情况如图:,第4章 函数,直接调用,间接调用,这两种递归调用都是无中止地调用自身,显然是不正确的。为了 防止递归调用无终止地进行,必须在函数内有终止递归调用的手段。,例4.8 用递归的方法求 n!,分析:计算n!的公式为:1 n =1或 0y = n*(n-1)! n 0可以将求n!转化为求(n-1)!,再继续转化为求(n-2)!,到1时应停止递归#include long power(
12、int n); void main() int n;long y;cout n;y=power(n);cout n “!=“ y endl; ,第4章 函数,long power(int n) long f;if(n1) f=n*power(n-1);elsef=1;return f; ,例4.8的递归过程分析,第4章 函数,例4.9 Hanoi塔问题,有三根针A、B、C,A针上有n个盘子,盘子大小不等,大的在下,小的在上,如图所示。要求将这n个盘子从A针移到C针,在移动过程中可以借助B针,每次只能移动一个盘子,并且在移动过程中三根针上的盘子都保持大盘在下,小盘在上。分析:将n个盘子从A针移到
13、C针可以分解为以下三个步骤: (1)将A针上的n-1个盘子借助C针移到B针上; (2)将A针上剩下的一个盘子移到C针上; (3)将B针上的n-1个盘子借助A针移到C针上。,第4章 函数,A,B,C,例4.9 Hanoi塔问题源程序,#include void Move(char x, char y); void Hanoi(int n, char one, char two, char three); void main() int n;cout n;cout “ y endl; ,第4章 函数,例4.9 Hanoi塔问题源程序(续),/函数Hanoi()将n-1个盘子从one针借助two针移
14、到three针 void Hanoi(int n, char one, char two, char three) if(n=1)Move(one, three);elseHanoi(n-1, one, three, two);Move(one, three);Hanoi(n-1, two, one, three); ,第4章 函数,程序运行结果: AC AB CB AC BA BC AC,运行演示,4.5 内联函数,内联函数与一般函数的区别在于它不是在调用时发生控制转移,而是在编译时将被调函数体嵌入到每一个函数调用处,节省了参数传递、控制转移等开销。对于一些规模较小、频繁调用的函数可声明为内
15、联函数,能提高程序运行效率。内联函数的定义:inline 类型说明符 函数名(参数及类型表) 函数体 注意:只有简单的函数才能成为内联函数,如函数体中不能有循环语句和switch语句等。内联函数的定义必须出现在内联函数第一次被调用之前。,第4章 函数,例4.10 使用内联函数,#include inline int Add(int a, int b) int x;x = a+b;return x; ,第4章 函数,程序运行结果:10+20=30 10+50=60 50+50=100,void main() int a, b, c;a = 10;b = 20;c = Add(a,b);cout
16、a “ + “ b “ = “ c endl;c = Add(a,50);cout a “ + 50 “ “ = “ c endl;c = Add(50,50);cout “50 + 50 “ “ = “ c endl; ,4.6 函数重载,在C+中可以定义多个相同名字的函数,只要它们形参的个数或类型不完全一致即可,编译程序根据实参与形参的类型及个数自动确定调用哪一个同名函数,这就是函数重载,这些同名函数称为重载函数。 例4.12 定义两个函数,分别求两个整数及两个实数的最大值。分析:在C语言中,要定义题中的函数,只能使用两个不同名函数实现,即定义 int max1(int x, int y)
17、double max2(double x, double y)在C+中,可通过定义两个重载函数实现,二者同名,如下:int max(int x, int y)double max(double x, double y),第4章 函数,例4.12 源程序,#include int max(int x, int y); double max(double x, double y); void main() int a=10, b=20 ,c; double x=200.3, y=400.6, z; c = max(a,b); z = max(x,y); cout c “ “ z endl; ,第4
18、章 函数,程序运行结果:int function float function 20,400.6,int max(int x, int y) cout y) return x; else return y; double max(double x, double y) cout y) return x; else return y; ,4.7 带默认参数值的函数,4.7.1 带默认参数值的函数在函数的声明或定义中可以预先给出默认的形参值,函数调用时,按从左到右的次序将实参和形参结合,如给出对应的实参,则采用实参值,否则采用预先给出的默认形参值 。例4.13 使用带默认参数值的函数求x的n次方(
19、n是正整数)。,第4章 函数,#include double power(double x=10.0, int n=2); void main() cout power(3, 5) endl; cout power(3) endl; cout power() endl; ,double power(double x, int n) int i;double s=1.0;for(i=1; i=n; i+)s *= x;return s; ,4.7 带默认参数值的函数,4.7.1 带默认参数值的函数(续)注意:默认形参值必须由右向左的顺序定义。如果某个参数有默认值,则其右面的参数必须都有默认值;如
20、果某个参数没有默认值,则其左面的参数都不能有默认值。例如:int max(int a, int b=10, int c=20); /正确int max(int a, int b=10, int c); /错误int max(int a=5, int b, int c=30); /错误在后两种情况下,调用语句 x = max(20, 30); 会出错!注意:在使用带默认参数值的函数时,只能在函数定义或函数声明中的一个位置给出默认值,不能在两个位置同时给出。还要保证在函数调用之前给出默认值。,第4章 函数,4.7 带默认参数值的函数,4.7.2 带默认参数值函数产生的二义性例4.14程序,第4章
21、函数,#include int add(int x=5, int y=6); float add(int x=5, float y=10.0); void main() int a; float b; a= add(10,20); b= add(10); cout “a= “ a endl; cout “b= “ b endl; ,int add(int x, int y) return x+y; float add(int x, float y) return x+y; ,b=add(10)语句产生二义性,可以认为该语句是调用第一个函数,也可以是第二个,因此编译器不能确定调用的是哪一个函数。
22、,4.8 变量的存储类别,4.8.1 内部变量与外部变量1. 内部变量在一个函数内部定义的变量是内部变量(也称为局部变量),它只在该函数范围内有效。 例如:,第4章 函数,void f1(int a) int b,c; void main() int m,n;,int i,a; for(i=0; i10; i+) int b; ,注意:在不同的作用范围内允许声明同名的变量,4.8 变量的存储类别,4.8.1 内部变量与外部变量(续)2. 外部变量在函数外部定义的变量是外部变量(也称为全局变量),它不属于任何一个函数。它的作用范围是:从外部变量的定义位置开始,到本文件的结尾。 例如:,第4章 函
23、数,int a,b; void f1( ) int x,y; void main() ,例4.15 使用全局变量和局部变量,#include int i=1; /全局变量,文件作用域 void main() cout“全局变量 i=“iendl; /输出1 int i=5; /函数局部变量,块作用域 int i; /块局部变量,块作用域 i=7; cout“块局部变量 i=“iendl; /输出7 cout“全局变量 i=“:iendl; /输出1,:使用全局变量 cout“函数局部变量 i=“iendl; /输出5 cout“全局变量 i=“:iendl; /输出1,:使用全局变量 ,第4章
24、 函数,程序运行结果:全局变量 i=1 块局部变量 i=7 全局变量 i=1 函数局部变量 i=5 全局变量 i=1,4.8 变量的存储类别,4.8.2 变量的存储类别变量在内存中的存储方式可以分为两大类,即静态存储方式与动态存储方式。静态存储方式是指在程序运行期间,分配固定的存储空间。全局变量和静态局部变量是静态存储方式。动态存储方式是在程序执行过程中,根据需要动态地分配存储空间。局部变量是动态存储方式。 1. 静态变量定义形式: static 数据类型 变量名特点:程序运行过程中变量始终存在,每次调用函数结束的值都被保留下来。仅初始化一次,每次调用它所在的函数时,不再重新初始化。若不指定初
25、值,自动指定初值为0。,第4章 函数,例4.16 输出14的阶乘,#include int fact( int n); void main() int i;for(i=1; i=4; i+) cout i “! = “ fact(i) endl; int fact(int n) static int f=1; /仅在第一次调用函数时执行一次f *= n;return f; ,第4章 函数,程序运行结果: 1!=1 2!=2 3!=6 4!=24,4.8 变量的存储类别,4.8.2 变量的存储类别(续)2. 自动变量定义形式: auto 数据类型 变量名特点:定义变量时,若不指定static或a
26、uto,则默认为自动变量。自动变量是动态存储方式。 每次调用它所在的函数时,都要重新分配存储空间,并初始化。函数调用结束,存储空间就释放。若不初始化,则初值是不确定的。,第4章 函数,例4.17 静态变量与动态变量的使用,#include void other(void); int i=1; / i 为全局变量,具有静态生存期。 void main(void) static int a; / a为静态局部变量,具有全局寿命,局部可见。 int b=-10; / b, c为动态局部变量,具有局部生存期。 int c=0; cout“-MAIN-n“; cout“ i: “i“ a: “a“ b:
27、 “b“ c: “cendl; c=c+8; other(); cout“-MAIN-n“; cout“ i: “i“ a: “a“ b: “b“ c: “cendl; i=i+10; other(); ,第4章 函数,例4.17 静态变量与动态变量的使用(续),void other(void) / a,b为静态局部变量,具有全局寿命,局部可见,/ 只第一次进入函数时被初始化。 static int a=2; static int b; int c=10; / C为动态局部变量,每次进入函数时都初始化。 a=a+2; i=i+32; c=c+5; cout“-OTHER-n“; cout“ i
28、: “i“ a: “a“ b: “b“ c: “cendl; b=a; ,第4章 函数,程序运行结果: -MAIN- i: 1 a: 0 b: -10 c: 0 -OTHER- i: 33 a: 4 b: 0 c: 15 -MAIN- i: 33 a: 0 b: -10 c: 8 -OTHER- i: 75 a: 6 b: 4 c: 15,例4.18 输出摄氏温度与华氏温度对照表,分析:编写一个函数求出指定摄氏温度对应的华氏温度值,在主函数中通过循环求出摄氏温度从099度对应的华氏温度值,并输出。转换公式为:F = 9/5*C +32其中F表示华氏温度,C为摄氏温度。程序如下: #includ
29、e #include int Convert(int c) int f;f = (int) (9.0/5*c + 32);return f; ,第4章 函数,例4.18(续一),#void main() cout “ | 0 1 2 3 4 5 6 7 8 9“ endl;cout “-|-“ endl;for(int i=0; i10; i+)cout setw(2) i*10 “ | “;for(int j=0; j10; j+)cout setw(3) Convert(i*10+j) “ “;cout endl; ,第4章 函数,例4.18(续二),程序运行结果:,第4章 函数,例4.1
30、9 用递归的方法计算从n个人中选取k个人的组合数,分析:从n个人中选取k个人的组合数 从n-1个人中选取k个人的组合数 + 从n-1个人中选取k-1个人的组合数 当n与k相等,或k等于0时,组合数为1,即有以下公式(comm表示组合数):1 n=k或k=0 comm(n, k)= comm(n-1, k)+ comm(n-1, k-1) n!=k 且k0,第4章 函数,例4.19(续),#include int comm(int n, int k); void main(void) int n, k;cout n k;cout n)return 0;else if(n=k) | (k=0)return 1;elsereturn comm(n-1, k) + comm(n-1, k-1); ,第4章 函数,程序运行结果: 请输入n和k的值:10 3 120,谢 谢!,