资源描述
,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,单击此处编辑母版标题样式,C+,程序设计,第,3,章,(2),函数的递归调用、重载、默认参数,1,主要内容,函数的递归调用,递归函数的执行过程,函数的重载,重载函数的注意事项,带默认值的形参,内联函数,程序的多文件结构,编译预处理,2,函数的递归调用,函数的递归调用:,直接递归调用:,指在一个函数,A,的定义中,出现了调用自身,A,的情况,这种调用关系称为直接递归调用,而函数,A,就是递归函数。,间接递归调用:,指在一个函数,A,的定义中,调用了函数,B,,,而在函数,B,的定义中又调用了函数,A,,,这种调用关系称为间接递归调用,而函数,A,也是递归函数。,递归算法的关键在于:,确立递归的公式,分析递归的结束条件,递归函数设计的一般方法:,先判断递归结束条件,再进行递归调用,3,【,例,】,(,用递归算法求,n!,。,),分析:确立递归公式:,n!=n (n-1)!,分析递归结束条件:当,n=0,或,n=1,时,,n!,的值为,1,。,#include,#include,int,fun (,int,n,),/,函数,fun(),的功能是:求,n!,if (n=0|n=1),return 1,;,/,先判断递归结束条件,return (n*,fun(n-1),),;,/,再进行递归调用,void main(),int,n;,cout,n;,if (n0),cout,“,输入数据有错!”,;,exit(0),;,cout,n “!=”,fun(n),endl,;,运行:,请输入一个正整数:,3 ,3!=6,4,main(),函数,调用,fun(3),时的执行过程:,main(),函数,调用,fun(3),时栈中的变化情况:,局部变量:,n=3,执行:,cout,fun(3),main(),函数,形参变量:,n=3,执行:,return 3*fun(2),fun(3),函数,形参变量:,n=2,执行:,return 2*fun(1),fun(2),函数,形参变量:,n=1,执行:,return 1,fun(1),函数,递推,递推,递推,回归,回归,回归,3,操作系统执行,状态和返回地址,main(),局部变量,n,3,操作系统执行,状态和返回地址,main(),局部变量,n,3,main(),函数执行,状态和返回地址,fun(3),形参变量,n,3,操作系统执行,状态和返回地址,main(),局部变量,n,3,main(),函数执行,状态和返回地址,fun(3),形参变量,n,2,fun(3),函数执行,状态和返回地址,fun(2),形参变量,n,3,操作系统执行,状态和返回地址,main(),局部变量,n,3,main(),函数执行,状态和返回地址,fun(3),形参变量,n,2,fun(3),函数执行,状态和返回地址,fun(2),形参变量,n,1,fun(2),函数执行,状态和返回地址,fun(1),形参变量,n,5,递归函数的执行过程,递归函数的执行过程:,递归函数的执行过程比较复杂,往往都存在着连续的递归调用,其执行过程可分为“递推”和“回归”两个阶段,先是一次一次不断的递推过程,直到符合递归结束条件,然后是一层一层的回归过程。,而其中的每一次递归调用,系统都要在栈中分配空间以保存该次调用的返回地址、参数、局部变量,因此在递推阶段,栈空间一直处于增长状态,直到遇到递归结束条件,然后进入回归阶段,栈空间反向依次释放。,在递归的执行过程中,递归结束条件非常重要,它控制“递推”过程的终止,因此在任何一个递归函数中,递归结束条件都是必不可少的,否则将会一直“递推”下去。导致无穷递归。,递归算法的缺点:,内存消耗巨大,且连续地调用和返回操作占用较多的,CPU,时间。,递归算法的优点:,算法描述简洁易懂。,6,【,例,】,(,分析下面递归函数的执行过程,并给出程序运行结果。),#include,void,sub(,char c,),cout,c;,if (c=a ),return,;,sub(c-1);,cout,c;,return,;,void main(),char,ch,=e;,sub(,ch,);,运行:,e d c b a b c d e,局部变量:,ch,=e,执行:,sub(e),main(),函数,形参变量:,c=e,执行:,cout,c;,sub(e-1),cout,c,return,sub(e),函数,形参变量:,c=d,执行:,cout,c;,sub(d-1),cout,c,return,sub(d),函数,递推,回归,递推,回归,形参变量:,c=b,执行:,cout,c;,sub(b-1),cout,c,return,sub(b),函数,形参变量:,c=a,执行:,cout,c;,if(c=a)return,sub(a),函数,递推,回归,形参变量:,c=c,执行:,cout,c;,sub(c-1),cout,c,return,sub(c),函数,递推,回归,递推,回归,7,【,例,】,(,用递归算法,计算从,n,个人中选择,k,个人组成一个委员会的不同组合数。,),分析:确立递归的公式:,由,n,人中选,k,人的组合数,=,由,n-1,人中选,k,人的组合数,+,由,n-1,人中选,k-1,人的组合数,分析递归的结束条件:,当,n=k,或,k=0,时,组合数为,1,。,#include,#include,int,comm,(,int,n,int,k,),/,函数,comm,(),的功能是:求,n,人中选,k,人的组合数,if (nk),return 0,;,if (n=k|k=0),return 1,;,/,先判断递归结束条件,return (,comm,(n-1,k),+,comm,(n-1,k-1),),;,/,再进行递归调用,void main(),int,n,k;,cout,n k;,if (n=0|k=0),cout,“,输入数据有错!”,;,exit(0),;,cout,“,由”,n “,人中选,”,k “,人的组合数,=”,comm,(n,k),endl,;,运行:,请输入正整数,n,和,k,:,8 5 ,由,8,人中选,5,人的组合数,=56,8,【,例,】,(汉诺塔问题:有,A,、,B,、,C,三根柱子,,A,柱上有,n,个大小不等的盘子,大盘在下,小盘在上。要求将这,n,个盘子从,A,柱移动到,C,柱,在移动的过程中可以借助,A,、,B,、,C,中任何一根柱子,但每次只允许移动一个盘子,且在移动过程中三根柱子上都必须保持大盘在下,小盘在上。),分析:,将,n,个盘子从,A,柱移动到,C,柱可分解为以下三个步骤:,将,A,柱上,n-1,个盘子移动到,B,柱(借助,C,柱),将,A,柱上剩下的一个盘子移动到,C,柱上,将,n-1,个盘子从,B,柱上移动到,C,柱上(借助,A,柱),分析得到,以上三个步骤包含两种操作:,将若干个盘子从一根柱上移动到另一根柱上,用递归函数,hanoi,(),实现。,将,1,个盘子从一根柱上移动到另一根柱上,用函数,move(),实现。,A,柱,B,柱,C,柱,9,#include,void,move(,char get,char put,),/,函数,move(),的功能是:将一个盘子从,get,柱上移动到,put,柱上,cout,get “,柱 ”,put “,柱”,endl,;,void,hanoi,(,int,n,char one,char two,char three,),/,函数,hanoi,(),的功能是:将,n,个盘子从,one,柱移动到,three,柱(借助,two,柱),if (n=1 ),move(one,three),;,return,;,/,先判断递归结束条件,else,hanoi,(n-1,one,three,two,),;,/,将,one,柱上,n-1,个盘子移动到,two,柱(借助,three,柱),进行递归调用,move(one,three),;,/,将,one,柱上剩下的一个盘子移动到,three,柱上,hanoi,(n-1,two,one,three,),;,/,将,two,柱上,n-1,个盘子移动到,three,柱(借助,one,柱),进行递归调用,10,void main(),int,n;,cout,n;,cout,“,将”,n “,个盘子从,A,柱移动到,C,柱的步骤:”,endl,;,hanoi,(,n,A,B,C,),;,运行:,请输入盘子数:,4 ,将,4,个盘子从,A,柱移动到,C,柱的步骤:,A,柱,B,柱,A,柱,C,柱,B,柱,C,柱,A,柱,B,柱,C,柱,A,柱,C,柱,B,柱,A,柱,B,柱,A,柱,C,柱,B,柱,C,柱,B,柱,A,柱,C,柱,A,柱,B,柱,C,柱,A,柱,B,柱,A,柱,C,柱,B,柱,C,柱,11,函数的重载,函数的重载:,重载的含义:,就是重新赋予新的含义。在,C+,的一个程序中可以用同一个函数名来命名多个函数,这些同名的函数在参数个数、类型上一定有所不同,分别代表不同的函数,当同名的多个函数出现在同一个作用域内时,称为重载函数。,重载的目的:,程序中经常将功能相近的函数在相同作用域内以相同函数名命名,从而形成重载函数,目的是方便使用,便于记忆。,【,例,】,int,add,(,int,x,int,y );,float,add,(,float,x,float,y );,float,add,(,double,x,double,y );,int,add,(,int,x,int,y );,int,add,(,int,x,int,y,int,z );,int,add,(,int,x,int,y,int,z,int,w );,函数名相同,但参数类型不同,函数名相同,但参数个数不同,12,重载函数的注意事项,注意事项:,重载函数的形参必须有所不同:参数个数或参数类型不同。,编译系统是根据实参与形参在类型及个数上的最佳匹配来选择调用哪一个函数。,【,例,】,定义重载函数时,要避免二义性,以免编译系统无法确定到底调用哪一个函数。,【,例,】,int,add,(,int,x,int,y,);,int,add,(,int,a,int,b,);,编译器不以,形参名,来区分。,int,add,(,int,x,int,y );,void,add,(,int,x,int,y);,编译器不以,返回值,来区分。,int,add,(,int,x,int,y,);,int,add,(,char,a,char,b,);,当调用,add(200,A),时,编译器无法确定到底调用哪一个函数。,13,【,例,】,#include,int,add(,int,x,int,y,),/,重载函数,cout,“,正在进行:两个,int,型数据相加,!tt”;,return (x+y),;,float,add(,float x,float y,),/,重载函数,cout,“,正在进行:两个,float,型数据相加,!tt”;,return (x+y),;,double,add(,double x,double y,),/,重载函数,cout,“,正在进行:两个,double,型数据相加,!tt”;,return (x+y),;,void main(),int,a1=5,b1=8;,float a2=5.1,b2=8.1;,double a3=5.2,b3=8.2;,cout,add(a1,b1),endl,;,cout,add(a2,b2),endl,;,cout,add(a3,b3),endl,;,cout,add(2,4),endl,;,cout,add(2.1,4.1),endl,;,cout,add(A,2),endl,;,运行:,正在进行:两个,int,型数据相加,!13,正在进行:两个,float,型数据相加,!13.2,正在进行:两个,double,型数据相加,!13.4,正在进行:两个,int,型数据相加,!6,正在进行:两个,double,型数据相加,!6.2,正在进行:两个,int,型数据相加,!115,14,带默认值的形参,默认形参值的作用:,函数声明时可以给形参指定一个默认值,调用时若给出实参,则形参采用实参值,若没有给出相应的实参,则该形参采用预先给出的默认值。,【,例,】,#include,int,add(,int,x=10,int,y=20,),/,带默认形参值的函数,cout,“,正在进行:”,x “+”y “=”;,return (x+y),;,void main(),cout,add(30,40),endl,;,cout,add(50),endl,;,cout,add(),endl,;,cout,add(2,4),endl,;,cout,add(A,1),endl,;,cout,add(A ),endl,;,运行:,正在进行:,30+40=70,正在进行:,50+20=70,正在进行:,10+20=30,正在进行:,50+4=54,正在进行:,65+49=114,正在进行:,65+20=85,15,带默认值的形参,带默认值的形参声明顺序:,函数必须按,从右往左,的顺序逐一声明带默认值的形参,且在带默认值的形参右面不能出现不带默认值的形参。只有这样规定后,在函数调用时才不会产生二义性。,【,例,】,int,add,(,int,x,int,y=2,int,z=3,);,当程序中调用,add(10),时,编译器调用,add(10,2,3),。,当程序中调用,add(10,20),时,编译器调用,add(10,20,3),。,int,add,(,int,x=1,int,y,int,z=3,);,当程序中调用,add(10,20),时,编译器无法确定调用以下那一个:,add(10,20,3),或,add(1,10,20),int,add,(,int,x=1,int,y=2,int,z=3,);,当程序中调用,add(),时,编译器调用,add(1,2,3),。,当程序中调用,add(10),时,编译器调用,add(10,2,3),。,当程序中调用,add(10,20),时,编译器调用,add(10,20,3),。,16,带默认值的形参,默认形参值仅能声明一次:,若函数定义在前、调用在后,默认形参值在函数定义时声明;若函数调用在前、定义在后,默认形参值必须在函数原型声明中给出,且在之后该函数定义时,不能再重复指定默认形参值。,【,例,】,#include,int,add(,int,x=1,int,y=2,);,/,带默认形参值的函数原型声明,void main(),cout,add(3,4),endl,;,cout,add(5),endl,;,cout,add(),endl,;,int,add(,int,x,int,y,),/,函数的定义性声明,cout,“,正在进行:”,x “+”y “=”;,return (x+y),;,运行:,正在进行:,3+4=7,正在进行:,5+2=7,正在进行:,1+2=3,17,带默认值的形参,默认形参值的作用域:,同一个函数在相同的作用域内,默认形参值应保持唯一,但在不同的作用域内,可提供不同的默认形参值。,【,例,】,#include,int,add(,int,x=1,int,y=2,),;,/,函数,add(),的全局原型声明,void main(),int,add(,int,x=3,int,y=4,),;,/,函数,add(),局部原型声明,void,fun(),;,/,函数,fun(),的原型声明,cout,add(),endl,;,/,使用局部默认形参值(实现,3+4,),fun();,void,fun(),/,函数,fun(),的定义性声明,cout,add(),endl,;,/,使用全局默认形参值(实现,1+2,),cout,add(10),endl,;,int,add(,int,x,int,y,),/,函数,add(),的定义性声明,cout,“,正在进行:”,x “+”y “=”;,return (x+y),;,运行:,正在进行:,3+4=7,正在进行:,1+2=3,正在进行:,10+2=12,18,内联函数,内联函数:,含义:,函数声明时前面加上,inline,为内联函数,含义是向编译系统建议:编译时在调用处用函数体进行置换,以节省了函数调用时控制转移、参数传递等开销。,实质:,是使用空间换取时间的方法,以加速程序的执行,当出现多次调用同一个内联函数时,程序本身占用的空间有所增加,若内联函数仅调用一次时,并不增加程序本身占用的存储空间。,注意:,对于用户指定的内联函数,编译器是否作为内联函数来处理由编译器自行决定。另外内联函数体内不能有,循环,、,switch,等复杂的结构控制语句。,【,例,】,#include,inline,float,area(,float r,),/,内联函数,return (3.1415*r*r),;,void main(),cout,“,半径,=”3 “n,面积,=”,area(3),endl,;,cout,“,半径,=”5 “n,面积,=”,area(5),endl,;,运行:,半径,=3,面积,=28.2735,半径,=5,面积,=78.5375,19,程序的多文件结构,多文件的程序:,在,C+,中,一个较大的程序通常被分解为若干个源程序文件,然后分别对各个源程序文件单独进行编译,这些源程序文件由一个工程文件进行管理,最后连接成一个完整的程序。,在多文件组成的程序中,一个源程序文件中定义的全局变量或函数,在另外一个源程序文件中被引用前,必须先对该全局变量或函数作外部声明。,外部类型变量的声明格式:,extern,类型 全局变量名,;,外部类型函数的声明格式:,extern,函数的原型声明,;,若一个源程序文件中定义的全局变量或函数,仅限于该源程序文件中使用,不能被程序中的其他源程序文件使用,在定义该全局变量或函数时前面需加上,static,。,内部类型变量的声明格式:,static,类型 全局变量名,;,内,部类型函数的声明格式:,static,函数的原型声明,;,20,【,例,】,(本程序由两个文件组成:,c1.cpp,、,c2.cpp,),/,文件,c1.cpp,内容,#include,int,a=5;,/,定义,a,为一般全局变量,可拓展到外部文件使用,static,int,b=8;,/,定义,b,为静态全局变量,只能在本文件中使用,extern,int,f0(,int,x,);,/,函数,f0(),的外部声明,其定义部分在,c2.cpp,中,int,f1(,int,x,int,y,),/,函数,f1(),的定义性声明,可拓展到外部文件使用,cout,“,进入函数,f1(),了,!t”;,return (x+y+a+b),;,extern,int,f2(,int,x,);,/,函数,f2(),的外部声明,其定义部分在,c2.cpp,中,extern,int,f3(,);,/,函数,f3(),的外部声明,其定义部分在,c2.cpp,中,extern,int,f4(,int,x,int,y,);,/,函数,f4(),的外部声明,其定义部分在,c2.cpp,中,void main(),/,cout,f0(7),endl,;,/,此句编译通过,但连接出错,,f0(),仅能在,c2.cpp,中使用,cout,f1(1,2),endl,;,cout,f2(3),endl,;,cout,f3(),endl,;,cout,f4(5,6),endl,;,运行:,进入函数,f1(),了,!16,进入函数,f2(),了,!15,进入函数,f3(),了,!,进入函数,f0(),了,!216,进入函数,f4(),了,!180,21,/,文件,c2.cpp,内容,#include,extern,int,a;,/,全局变量,a,的外部声明,其定义部分在,c1.cpp,中,extern,int,b;,/,全局变量,b,的外部声明,其定义部分在,c1.cpp,中,static,int,f0(,int,x,),/,函数,f0(),的定义性声明,只能在本文件中使用,cout,“,进入函数,f0(),了,!t”;,return (x*x),;,int,f2(,int,x,),/,函数,f2(),的定义性声明,可拓展到外部文件使用,cout,“,进入函数,f2(),了,!t”;,/b+;,/,此句编译通过,但连接出错,,b,仅能在,c1.cpp,中使用,return (x*a ),;,int,f3(,),/,函数,f3(),的定义性声明,可拓展到外部文件使用,cout,“,进入函数,f3(),了,!t”;,return (,f0(+a),*a ),;,int,f4(,int,x,int,y,),/,函数,f4(),的定义性声明,可拓展到外部文件使用,cout,“,进入函数,f4(),了,!t”;,return (x*y*a ),;,22,编译预处理,编译预处理:,指源程序文件在被编译之前,由编译预处理程序对其所做的加工处理工作。,编译预处理程序不是,C+,编译程序的组成部分。,编译预处理程序在处理源程序文件时,是将预处理好的程序写入到一个临时文件中,并将该临时文件作为编译程序的输入文件,即编译程序是对该临时文件进行编译,产生目标文件。,编译预处理不会影响源程序文件中的内容。,编译预处理命令:,一律以,#,开头,以回车符结束,末尾不加分号,且单独占用一行。编译预处理命令通常放在源程序文件的开始部分。,编译预处理命令有三种:,包含文件,宏定义,条件编译,23,编译预处理,#include,命令,包含文件:,格式,1,:,#include,格式,2,:,#include,“,文件名,”,处理过程:,将命令中所指定的文件内容嵌入到当前源程序文件的该,#include,命令处,成为当前源程序文件的一个组成部分。,#include,:,表示按标准方式查找,即从,C+,系统目录下的,include,子目录中开始查找所要包含的文件。,C+,的,库函数一般都存放在编译器约定的,include,子目录下,当需要使用库函数时通常采用该格式。,#include,“,文件名,”,:,表示先从当前目录(即当前源程序文件所在的目录)开始查找所要包含的文件,若找不到,再按标准方式查找,到,C+,系统目录下的,include,子目录中继续查找。当需要包含用户自定义的文件时,通常采用该格式。,#include,“,带路径的文件名,”,:,若所要包含的文件既不在,include,子目录中,也不在当前目录中,必须指明文件的路径。,例:,#include,“,E:ABC123file1,”,24,编译预处理,#define,命令,不带参数的宏定义:,格式,1,:,#define,宏名,格式,2,:,#define,宏名 宏体,处理过程:,定义一个宏名,若宏名后面跟有宏体,则将其后程序中所有出现该宏名的地方用相应的宏体替换之,这种替换过程称为“宏替换”或“宏展开”。,几点说明:,宏名是一个标识符,通常用大写字母表示,以便与程序中的变量名区别。,宏定义可以出现在程序中的任何位置,宏名的作用域是从定义处开始到文件结尾处结束。若要提前终止宏名的作用域,可使用预处理命令:,#,undef,宏名,在同一个作用域内,同一个宏名不允许定义两次或两次以上,否则编译预处理在进行宏替换时,会出现二义性。,在一个宏定义中可以使用前面已定义过的宏名。,25,编译预处理,#define,命令,宏替换时,只对宏名做简单的替换,不做任何计算,也不做任何语法检查,若宏定义时书写不正确,会得到不正确的结果或编译时出现语法错误。,当宏名出现在字符串中时,编译预处理不进行宏替换。,【,例,】,#include,#define,A,3+5,#define,B,A,*,A,/,替换后:,#define B 3+5*3+5,#define,C,(,A,)*(,A,),/,替换后:,#define C (3+5)*(3+5),#define,D “,A,”,#define,E,“,输出:,t”,void main(),cout,E,“B,南,C,京,A”,endl,;,/,替换后:,cout,“,输出:,t”“B,南,C,京,A”,endl,;,cout,E,A,endl,;,/,替换后:,cout,“,输出:,t”3+5,endl,;,cout,E,B,endl,;,/,替换后:,cout,“,输出:,t”3+5*3+5 ,endl,;,cout,E,C,endl,;,/,替换后:,cout,“,输出:,t”(3+5)*(3+5),endl,;,cout,E,D,endl,;,/,替换后:,cout,“,输出:,t”“A”,endl,;,运行:,输出:,B,南,C,京,A,输出:,8,输出:,23,输出:,64,输出:,A,26,编译预处理,#define,命令,带参数的宏定义:,格式:,#define,宏名,(,形参表,),宏体,形参表,由若干个参数名组成,参数之间以逗号分隔。,宏体,由若干个参数组成的一个式子。,处理过程:,类似于函数的处理过程,先将宏调用中的实参替换宏定义中的形参,即先进行参数的替换,再进行宏替换。,几点说明:,宏名是一个标识符,与后面形参表的左括号之间不得有空格。,所谓参数的替换,是指用宏调用中的每一个实参字符序列去替换宏定义中的相应形参,且只做简单的替换,不做任何计算。,一个宏定义应在一行内定义完,以换行符结束,若多于一行在行尾加上转义符“,”,。,27,【,例,】,#include,#define,PRINT(a),cout,“a=”a,endl,;,#define,print(a,b),cout,“ab=”a*b,endl,;,cout,“ab=”a/b,endl,;,void main(),int,x,y;,cout,x y;,PRINT(x),/,替换后:,cout,“a=”x,endl,;,PRINT(y),/,替换后:,cout,“a=”y,endl,;,PRINT(x+y),/,替换后:,cout,“a=”x+y,endl,;,PRINT(1+2),/,替换后:,cout,“a=”1+2,endl,;,print(x,y),/*,替换后:,cout,“ab=”x*y,endl,;,cout,“ab=”x/y,endl,;*/,print(2+6,4+7),/*,替换后:,cout,“ab=”,2+6*4+7,endl,;,cout,“ab=”,2+6/4+7,endl,;*/,运行:,请输入两个整数:,8 5 ,a=8,a=5,a=13,a=3,a b=40,a b=1,a b=33,a b=10,28,编译预处理,条件编译命令,使用宏名作为程序段是否被编译的条件:,格式,1,:,#,ifdef,宏名,格式,3,:,#,if,n,def,宏名,程序段 程序段,#,endif,#,endif,格式,2,:,#,ifdef,宏名,格式,4,:,#,if,n,def,宏名,程序段,1,程序段,1,#else#else,程序段,2,程序段,2,#,endif,#,endif,作用:,通常源程序中的所有语句都将被编译,但有时希望源程序中的某个程序段只有在满足某种条件时才被编译,而条件不满足时则不被编译,就好像该程序段从源程序中消失了一样,此时可选用上面格式之一来实现有条件的编译。,29,编译预处理,条件编译命令,几点说明:,以格式,1,为例,当源程序中使用,#,ifdef,宏名,程序段,#,endif,结构时,若该程序段要被编译,可在该结构的前面加上一条定义宏名的预处理命令(,#define,宏名,);若该程序段不被编译,则将其前面的宏名定义命令删除掉(,删除,#define,宏名,),这种做法比从源程序中将该程序段整体删除要简单,且不容易出错。,编译时根据宏名是否被定义,决定某程序段是否被编译,这种方法常用于程序调试中。调试程序时,常在程序中加入一些语句来输出调试信息,而调试结束后这些新加入的语句就不再需要了,因此可考虑将这些要加入的语句用条件编译结构括起来一同加入到程序中。,条件编译命令的另一重要用途:,将其应用于被包含的文件中,可实现在一个源程序文件中,若,多次出现,#include“,同一个被包含文件”,命令时,,只有第一次的包含命令起作用,其余的包含命令都不起作用。,30,【,例,】,/,文件,f1.h,中定义了一个求阶乘函数,aaa,(),double,aaa,(,int,n,),/,函数,aaa,(),的功能是:求,n!,double t=1;,for (,int,i=1;i=n;i+)t*=i;,return t;,/,文件,f2.h,中定义了一个求组合函数,bbb,(),#include “f1.h”,double,bbb,(,int,m,int,k,),/,函数,bbb,(),的功能是:求,C,m,k,=m!/(k!(m-k)!),return,(,aaa,(m),/(,aaa,(k),*,aaa,(m-k),);,/,文件,f3.cpp,中定义了,main(),函数求:,3!+C,8,5,+7!+C,9,8,+4!,#include,#include“f1.h”,#include“f2.h”,void main(),cout,“,(,3!+C,8,5,+7!+C,9,8,+4!,),=”;,cout,(,aaa,(3)+,bbb,(8,5)+,aaa,(7)+,bbb,(9,8)+,aaa,(4),),endl,;,编译出错!,在文件,f3.cpp,中文件,f1.h,被包含了两次,函数,aaa,(),出现重复定义,!,31,【,例,】,(上例中的文件,f1.h,、,f2.h,内容修改如下,文件,f3.cpp,内容不变),/,文件,f1.h,中定义了一个求阶乘函数,aaa,(),#,if,n,def,f1,#define f1,double,aaa,(,int,n ),/,函数,aaa,(),的功能是:求,n!,double t=1;,for (,int,i=1;i=n;i+)t*=i;,return t;,#,endif,/,文件,f2.h,中定义了一个求组合函数,bbb,(),#,if,n,def,f2,#define f2,#include “f1.h”,double,bbb,(,int,m,int,k ),/,函数,bbb,(),的功能是:求,C,m,k,=m!/(k!(m-k)!),return (,aaa,(m)/(,aaa,(k)*,aaa,(m-k);,#,endif,32,/,文件,f3.cpp,中定义了,main(),函数求:,3!+C,8,5,+7!+C,9,8,+4!,#include,#include“f1.h”,#include“f2.h”,void main(),cout,“,(,3!+C,8,5,+7!+C,9,8,+4!,),=”;,cout,(,aaa,(3)+,bbb,(8,5)+,aaa,(7)+,bbb,(9,8)+,aaa,(4),),endl,;,运行:,(,3!+C,8,5,+7!+C,9,8,+4!,),=5135,33,
展开阅读全文