1、第三章第三章 函数函数C+语言程序设计1第1页 前一页 休息本章主要内容本章主要内容l函数申明和调用函数申明和调用l函数间参数传递函数间参数传递l内联函数内联函数l带缺省形参值函数带缺省形参值函数l函数重载函数重载l函数模板函数模板lC+系统函数系统函数2第2页 前一页 休息函数申明函数申明l函数是面向对象程序设计中基本抽象单函数是面向对象程序设计中基本抽象单元,是对功效抽象元,是对功效抽象l函数申明语法形式函数申明语法形式类型标识符 函数名(形式参数表)语句序列函数申明与使用若无参数,写void是被初始化内部变量,寿命和可见性仅限于函数内部若无返回值,写void3第3页 前一页 休息函数申明
2、函数申明l形式参数表形式参数表 name1,name2,.,namenl函数返回值函数返回值由 return 语句给出,比如:return 0无返回值函数(void类型),无须写return语句。函数申明与使用4第4页 前一页 休息函数调用函数调用l调用前先说明函数原型:调用前先说明函数原型:在调用函数说明部分,或程序文件开头全部函数之前,按以下形式说明:类型标识符 被调用函数名(含类型说明形参表);l调用形式调用形式 函数名(实参列表)l嵌套调用嵌套调用函数不允许嵌套申明,但能够嵌套调用。l递归调用递归调用函数直接或间接调用本身。函数申明与使用5第5页 前一页 休息例例3-1 编写一个求编写
3、一个求xn次方函数次方函数#include doublepower(double x,int n);void main(void)cout 5 to the power 2 is power(5,2)endl;doublepower(double x,int n)double val=1.0;while(n-)val=val*x;return(val);函数申明与使用6第6页 前一页 休息运行结果:运行结果:5 to the power 2 is 25例例3-1 编写一个求编写一个求xn次方函数次方函数函数申明与使用7第7页 前一页 休息例例3-2 数制转换数制转换题目:题目:输入一个输入一个
4、8位二进制数,将其转换位二进制数,将其转换为十进制数输出。为十进制数输出。比如:比如:11012=1(23)+1(22)+0(21)+1(20)=1310 所以,假如输入所以,假如输入1101,则应输出,则应输出13函数申明与使用8第8页#include double power(double x,int n);void main(void)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;9第9页double power(double
5、 x,int n)double val=1.0;while(n-)val*=x;return(val);运行结果:运行结果:Enter an 8 bit binary number 01101001Decimal value is 10510第10页 前一页 休息例例3-3 编写程序求编写程序求值值其中其中arctan用以下形式级数计算:用以下形式级数计算:直直到到级级数数某某项项绝绝对对值值小小于于10-15为为止止;和和x均为均为double型。型。函数申明与使用11第11页#includevoid main()double a,b;double arctan(double x);a=16
6、.0*arctan(1/5.0);b=4.0*arctan(1/239.0);/注意:因为整数相除结果取整,注意:因为整数相除结果取整,/假如参数写假如参数写1/5,1/239,结果就都是,结果就都是0 coutPI=a-b1e-15)f=e/i;r=(i%4=1)?r+f:r-f ;e=e*sqr;i+=2;return r;运行结果:运行结果:PI=3.1415913第13页运行结果:运行结果:PI=3.1415914第14页 前一页 休息例例3-4l寻找并输出寻找并输出11999之间数之间数m,它满足,它满足m、m2和和m3均为回文数。均为回文数。回文:各位数字左右对称整数。比如:11满
7、足上述条件 112=121,113=1331。l分析:分析:10取余方法,从最低位开始,依次取出该数各位数字。按反序重新组成新数,比较与原数是否相等,若相等,则原数为回文。函数申明与使用15第15页#include void main()bool symm(long n);long m;for(m=11;m1000;m+)if(symm(m)&symm(m*m)&symm(m*m*m)coutm=m m*m=m*m m*m*m=m*m*mendl;16第16页bool symm(long n)long i,m;i=n;m=0;while(i)m=m*10+i%10;i=i/10 ;return
8、(m=n);17第17页运行结果:运行结果:m=11 m*m=121 m*m*m=1331m=101 m*m=10201 m*m*m=1030301m=111 m*m=12321 m*m*m=136763118第18页 前一页 休息例例3-5计算以下公式,并输出结果:计算以下公式,并输出结果:其中其中r、s值由键盘输入。值由键盘输入。SIN x近似值近似值按以下公式计算,计算精度为按以下公式计算,计算精度为10-6:函数申明与使用19第19页#include#includevoid main()double k,r,s;double tsin(double x);coutr;couts;if(
9、r*r=s*s)k=sqrt(tsin(r)*tsin(r)+tsin(s)*tsin(s);else k=tsin(r*s)/2;coutk=p);return g;运行结果:r=5s=81.3778121第21页 前一页 休息例例3-6 投骰子随机游戏投骰子随机游戏游游戏戏规规则则是是:每每个个骰骰子子有有六六面面,点点数数分分别别为为1、2、3、4、5、6。游游戏戏者者在在程程序序开开始始时时输输入入一一个个无无符符号号整整数,作为产生随机数种子。数,作为产生随机数种子。每每轮轮投投两两次次骰骰子子,第第一一轮轮假假如如和和数数为为7或或11则则为为胜胜,游游戏戏结结束束;和和数数为为2
10、、3或或12则则为为负负,游游戏戏结结束束;和和数数为为其其它它值值则则将将此此值值作作为为自自己己点点数数,继继续续第第二二轮轮、第第三三轮轮.直直到到某某轮轮和和数数等等于于点点数数则则取取胜胜,若若在在以以前前出出现现和数为和数为7则为负。则为负。由由rolldice函函数数负负责责模模拟拟投投骰骰子子、计计算算和和数数并并输输出出和数。和数。函数申明与使用22第22页lrand函数原型:int rand(void);所需头文件:功效和返回值:求出并返回一个伪随机数lsrand函数原型:void srand(unsigned int seed);参数:seed产生随机数种子。所需头文件:
11、功效:为使rand()产生一序列伪随机整数而设置起始点。使用1作为seed参数,能够重新初化rand()。23第23页#include#include int rolldice(void);void main()int gamestatus,sum,mypoint;unsigned seed;coutseed;/输入随机数种子输入随机数种子 srand(seed);/将种子传递给将种子传递给rand()sum=rolldice();/第一轮投骰子、计算和数第一轮投骰子、计算和数24第24页 switch(sum)case 7:/假如和数为假如和数为7或或11则为胜则为胜,状态为状态为1 cas
12、e 11:gamestatus=1;break;case 2:/和数为和数为2、3或或12则为负则为负,状态为状态为1 case 3:case 12:gamestatus=2;break;default:/其它情况其它情况,游戏尚无结果游戏尚无结果,状态为状态为0,记下点数记下点数,为下一轮做准为下一轮做准备备 gamestatus=0;mypoint=sum ;coutpoint is mypointendl;break;25第25页 while(gamestatus=0 )/只要状态仍为只要状态仍为 0,就继续进行下一就继续进行下一轮轮 sum=rolldice();if(sum=mypo
13、int)/某轮和数等于点数则取胜某轮和数等于点数则取胜,状态置为状态置为1 gamestatus=1 ;else if(sum=7 )/出现和数为出现和数为7则为负则为负,状态置为状态置为2 gamestatus=2;/当状态不为当状态不为0时上面循环结束时上面循环结束,以下程序段输出游戏结果以下程序段输出游戏结果 if(gamestatus=1 )coutplayer winsn;else coutplayer losesn;26第26页int rolldice(void)/投骰子、计算和数、输出和数投骰子、计算和数、输出和数 int die1,die2,worksum;die1=1+ran
14、d()%6;die2=1+rand()%6;worksum=die1+die2;coutplayer rolled die1+die2=worksumendl;return worksum;27第27页运行结果运行结果2:Please enter an unsigned integer:23player rolled 6+3=9point is 9player rolled 5+4=9player wins28第28页 前一页 休息函数调用执行过程函数调用执行过程函数申明与使用main()调fun()结束fun()返回保留:返回地址当前现场恢复:主调程序现场返回地址29第29页 前一页 休息嵌
15、套调用嵌套调用函数申明与使用main调fun1()结束fun1()调fun2()返回fun2()返回30第30页 前一页 休息例例3-7 输入两个整数,求平方和。输入两个整数,求平方和。#include#include void main(void)void main(void)int a,b;int a,b;int fun1(int x,int y);int fun1(int x,int y);cinab;cinab;coutacouta、b b平平方方和和:fun1fun1(a,b)endl;(a,b)endl;函数申明与使用31第31页int int fun1fun1(int x,int
16、 y)(int x,int y)int int fun2fun2(int m);(int m);return(fun2(x)+fun2(y);return(fun2(x)+fun2(y);int int fun2fun2(int m)(int m)return(m*m);return(m*m);运行结果:运行结果:3 43 4a a、b b平方和:平方和:252532第32页 前一页 休息递归调用递归调用l函数直接或间接地调用本身,称为递归调用。l递归过程两个阶段:递推:4!=43!3!=32!2!=21!1!=10!0!=1未知 已知回归:4!=43!=243!=32!=62!=21!=21
17、!=10!=10!=1未知未知 已知已知函数申明与使用33第33页 前一页 休息例例3-8 求求n!分析:计算n!公式以下:这是一个递归形式公式,应该用递归函数实现。函数申明与使用34第34页源程序:源程序:#include#include long long facfac(int n)(int n)long f;long f;if(n0)if(n0)coutn0,data error!endl;coutn0,data error!endl;else if(n=0)f=1;else if(n=0)f=1;else f=else f=facfac(n-1)*n;(n-1)*n;return(f)
18、;return(f);35第35页void mainvoid main()long fac(int n);long fac(int n);int n;int n;long y;long y;coutEnter a positive integer:;coutn;cinn;y=y=facfac(n);(n);coutn!=yendl;coutn!=yendl;运行结果:运行结果:Enter a positive integer:8Enter a positive integer:88!=403208!=4032036第36页 前一页 休息例例3-9l用递归法计算从用递归法计算从n个人中选择个人中
19、选择k个人组个人组成一个委员会不一样组合数。成一个委员会不一样组合数。l分析:分析:由n个人里选k个人组合数=由n-1个人里选k个人组合数 +由n-1个人里选k-1个人组合数当n=k或k=0时,组合数为1函数申明与使用37第37页#includevoid main()int n,k;int comm(int n,int k);cinnk;coutcomm(n,k)n )return 0;else if(n=k|k=0 )return 1;else return comm(n-1,k)+comm(n-1,k-1);运行结果:18 5856838第38页 前一页 休息例例3-10 汉诺塔问题汉诺塔
20、问题有三根针有三根针A、B、C。A针上有针上有N个盘子,个盘子,大在下,小在上,要求把这大在下,小在上,要求把这N个盘子从个盘子从A针移针移到到C针,在移动过程中能够借助针,在移动过程中能够借助B针,每次只针,每次只允许移动一个盘,且在移动过程中在三根针允许移动一个盘,且在移动过程中在三根针上都保持大盘在下,小盘在上。上都保持大盘在下,小盘在上。函数申明与使用ABC39第39页分析:分析:将将n 个盘子从个盘子从A针移到针移到C针能够分解为下面三个步骤:针能够分解为下面三个步骤:将将A 上上n-1个盘子移到个盘子移到 B针上(借助针上(借助C针)针);把把A针上剩下一个盘子移到针上剩下一个盘子
21、移到C针上针上;将将n-1个盘子从个盘子从B针移到针移到C针上(借助针上(借助A针)针);实际上,上面三个步骤包含两种操作:实际上,上面三个步骤包含两种操作:将多个盘子从一个针移到另一个针上,这是一个递将多个盘子从一个针移到另一个针上,这是一个递归过程。归过程。hanoi函数实现。函数实现。将将1个盘子从一个针上移到另一针上。个盘子从一个针上移到另一针上。用用move函数实现。函数实现。40第40页#include void move(char getone,char putone)cout getone putoneendl;void hanoi(int n,char one,char tw
22、o,char three)void move(char getone,char putone);if(n=1)move(one,three);else hanoi(n-1,one,three,two);move(one,three);hanoi(n-1,two,one,three);41第41页void main()void hanoi(int n,char one,char two,char three);int m;coutm;coutthe steps to moving m diskes:CA-BC-BA-CB-AB-CA-C43第43页 前一页 休息函数参数传递机制函数参数传递机制
23、传递参数值传递参数值l在函数被调用时才分配形参存放单在函数被调用时才分配形参存放单元。元。l实参能够是常量、变量或表示式。实参能够是常量、变量或表示式。l实参类型必须与形参相符。实参类型必须与形参相符。l传递时是传递参数值,即单向传递。传递时是传递参数值,即单向传递。函数申明与使用44第44页 前一页 休息函数参数传递机制函数参数传递机制 参数值传递举例参数值传递举例XN被调函数:被调函数:主调函数:主调函数:3 2.5AD=power(A,3)2.53double power(double X,int N)函数申明与使用45第45页 前一页 休息例例3-11 输入两输入两 整数交换后输出整数
24、交换后输出#includevoid Swap(int a,int b);int main()int x(5),y(10);coutx=x y=yendl;Swap(x,y);coutx=x y=yendl;return 0;函数申明与使用46第46页void Swap(int a,int b)int t;t=a;a=b;b=t;运行结果运行结果:x=5 y=10 x=5 y=1047第47页 前一页 休息函数参数传递函数参数传递 用引用做形参用引用做形参l引用引用(&)是标识符别名是标识符别名,比如比如:int i,j;int&ri=i;/建立一个int型引用ri,并将其 /初始化为变量i一个
25、别名j=10;ri=j;/相当于 i=j;l申明一个引用时,必须同时对它进行初始化,申明一个引用时,必须同时对它进行初始化,使它指向一个已存在对象。使它指向一个已存在对象。l一旦一个引用被初始化后,就不能改为指向一旦一个引用被初始化后,就不能改为指向其它对象。其它对象。l引用能够作为形参引用能够作为形参 void swap(int&a,int&b).函数申明与使用48第48页 前一页 休息例例3-12 输入两个整数交换后输出输入两个整数交换后输出#includevoid Swap(int&a,int&b);int main()int x(5),y(10);coutx=x y=yendl;Swa
26、p(x,y);coutx=x y=yendl;return 0;函数申明与使用49第49页void Swap(int&a,int&b)int t;t=a;a=b;b=t;运行结果运行结果:x=5 y=10 x=10 y=550第50页t=a;x x5t5x 地址a ax xy y510y 地址x 地址a ab by 地址x 地址a ab bx x10y y10a=bb=t;y5t5y 地址b bx xy y105Swap(x,y);51第51页 前一页 休息例例3-13 引用调用举例引用调用举例#include#include void fiddle(int in1,int&in2);int
27、main()int count=7,index=12;cout The values are;coutsetw(5)count;coutsetw(5)indexendl;fiddle(count,index);cout The values are;coutsetw(5)count;coutsetw(5)indexendl;return 0;函数申明与使用52第52页void fiddle(int in1,int&in2)in1=in1+100;in2=in2+100;cout The values are;coutsetw(5)in1;coutsetw(5)in2endl;运行结果:运行结果
28、:The values are 7 12 The values are 107 112 The values are 7 11253第53页 前一页 休息内联函数申明与使用内联函数申明与使用l申明时使用关键字申明时使用关键字 inline。l编译时在调用处用函数体进行替换编译时在调用处用函数体进行替换,节节约了参数传递、控制转移等开销。约了参数传递、控制转移等开销。l注意:注意:内联函数体内不能有循环语句和switch语句。内联函数申明必须出现在内联函数第一次被调用之前。对内联函数不能进行异常接口申明。内联函数54第54页 前一页 休息例例3-14 内联函数应用举例内联函数应用举例#inclu
29、deinline double CalArea(double radius)return 3.14*radius*radius;int main()double r(3.0);double area;area=CalArea(r);coutareaendl;return 0;内联函数55第55页 前一页 休息缺省形参值作用缺省形参值作用l函数在申明时能够预先给出默认形参值,调函数在申明时能够预先给出默认形参值,调用时如给出实参,则采取实参值,不然采取用时如给出实参,则采取实参值,不然采取预先给出默认形参值。预先给出默认形参值。l比如:比如:int add(int x=5,int y=6)ret
30、urn x+y;void main(void)add(10,20);/10+20 add(10);/10+6 add();/5+6带缺省形参值函数56第56页 前一页 休息缺省形参值说明次序缺省形参值说明次序l缺省形参值必须缺省形参值必须从右向左从右向左次序申明,而次序申明,而且在缺省形参值右面不能有非缺省形参且在缺省形参值右面不能有非缺省形参值参数。因为调用时实参取代形参是从值参数。因为调用时实参取代形参是从左向右次序。左向右次序。l例:例:int add(int x,int y=5,int z=6);/正确int add(int x=1,int y=5,int z);/错误int add(
31、int x=1,int y,int z=6);/错误带缺省形参值函数57第57页 前一页 休息缺省形参值与函数调用位置缺省形参值与函数调用位置l调用出现在函数体实现之前时,缺省形参值必调用出现在函数体实现之前时,缺省形参值必须在函数原形中给出;而当调用出现在函数体须在函数原形中给出;而当调用出现在函数体实现之后时,缺省形参值需在函数实现时给出。实现之后时,缺省形参值需在函数实现时给出。l例:例:int add(int x=5,int y=6);void main(void)add();/调用在实现前int add(int x,int y)return x+y;int add(int x=5,i
32、nt y=6)return x+y;void main(void)add();/调用在实现后带缺省形参值函数58第58页 前一页 休息缺省形参值作用域缺省形参值作用域l在相同作用域内,缺省形参值说明应保持在相同作用域内,缺省形参值说明应保持唯一,但假如在不一样作用域内,允许说唯一,但假如在不一样作用域内,允许说明不一样缺省形参。明不一样缺省形参。l例:例:int add(int x=1,int y=2);void main(void)int add(int x=3,int y=4);add();/使用局部缺省形参值(实现3+4)void fun(void).add();/使用全局缺省形参值(实
33、现1+2)带缺省形参值函数59第59页 前一页 休息例例3-15 带缺省形参值函数举例带缺省形参值函数举例#include#include int get_volume(int length,int width=2,int height=3);int main()int x=10,y=12,z=15;cout Some box data is ;cout get_volume(x,y,z)endl;cout Some box data is ;cout get_volume(x,y)endl;cout Some box data is ;cout get_volume(x)endl;cout
34、Some box data is;cout get_volume(x,7)endl;cout Some box data is;cout get_volume(5,5,5)endl;return 0;带缺省形参值函数60第60页int get_volume(int length,int width,int height)coutsetw(5)length setw(5)widthsetw(5)height;return length*width*height;运行结果:运行结果:Some box data is 10 12 15 1800Some box data is 10 12 3 360
35、Some box data is 10 2 3 60Some box data is 10 7 3 210Some box data is 5 5 5 12561第61页 前一页 休息重载函数申明重载函数申明lC+允许功效相近函数在相同作用域内允许功效相近函数在相同作用域内以相同函数名申明,从而形成重载。方以相同函数名申明,从而形成重载。方便使用,便于记忆。便使用,便于记忆。l例:例:形参类型不一样int add(int x,int y);float add(float x,float y);形参个数不一样int add(int x,int y);int add(int x,int y,int
36、 z);函 数 重 载62第62页 前一页 休息注意事项注意事项不要将不一样功效函数申明为重载函数,以免出现调用结果误解、混同。这么不好: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)return x+y;float add(float x,float y)return x-y;函 数 重 载重载函数形参必须不一样:个数不一样或类型不一样。编译程序将依据实参和形参类型及个数最正确匹配来选择
37、调用哪一个函数。63第63页 前一页 休息例例3-16 重载函数应用举例重载函数应用举例编写三个名为编写三个名为add重载函数,分别实现两整数相重载函数,分别实现两整数相加、两实数相加和两个复数相加功效。加、两实数相加和两个复数相加功效。#includestruct complexdouble real;double imaginary;64第64页void main(void)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
38、,complex c2);coutmn;coutinteger m+n=add(m,n)endl;65第65页coutxy;coutreal number x+y=add(x,y)endl;coutc1.realc1.imaginary;coutc2.realc2.imaginary;c3=add(c1,c2);coutcomplex number(c1.real,c1.imaginary)+(c2.real,c2.imaginary)=(c3.real,c3.imaginary)n;66第66页int add(int m,int n)return m+n;double add(double
39、x,double y)return x+y;complex add(complex c1,complex c2)complex c;c.real=c1.real+c2.real;c.imaginary=c1.imaginary+c2.imaginary;return c;67第67页运行结果:运行结果:Enter two integer:3 5integer 3+5=8Enter two real number:2.3 5.8real number 2.3+5.8=8.1Enter the first complex number:12.3 45.6Enter the second compl
40、ex number:56.7 67.8complex number(12.3,45.6)+(56.7,67.8)=(69,113.4)68第68页 前一页 休息函数模板申明函数模板申明l函数模板能够用来创建一个通用功效函数模板能够用来创建一个通用功效函数,以支持各种不一样形参,深入函数,以支持各种不一样形参,深入简化重载函数函数体设计。简化重载函数函数体设计。l申明方法:申明方法:template 函数申明 函 数 模 板69第69页 前一页 休息例例3-17 求绝对值函数模板求绝对值函数模板#includetemplateT abs(T x)return x0?-x:x;void main(
41、)int n=-5;double d=-5.5;coutabs(n)endl;coutabs(d)endl;函 数 模 板70第70页l运行结果:运行结果:55.5l分析分析编译器从调用abs()时实参类型,推导出函数模板类型参数。比如,对于调用表示式abs(n),因为实参n为int型,所以推导出模板中类型参数T为int。当类型参数含义确定后,编译器将以函数模板为样板,生成一个函数:int abs(int x)return x0?-x:x;71第71页 前一页 休息C+系统函数系统函数lC+系统库中提供了几百个函数可供系统库中提供了几百个函数可供程序员使用。程序员使用。比如:求平方根函数(sp
42、rt)、求绝对值函数(abs)等。l使用系统函数时要包含对应头文件。使用系统函数时要包含对应头文件。比如:math.h使用C+系统函数72第72页 前一页 休息例例3-18 系统函数应用举例系统函数应用举例l题目:题目:从键盘输入一个角度值,求出该角度正弦值、余弦值和正切值。l分析:分析:系统函数中提供了求正弦值、余弦值和正切值函数:sin()、cos()、tan(),函数说明在头文件math.h中。使用C+系统函数73第73页#include#includeconst double pi(3.14159265);void main()double a,b;cina;b=a*pi/180;co
43、utsin(a)=sin(b)endl;coutcos(a)=cos(b)endl;couttan(a)=tan(b)(“活动子集”栏)Visual C+Documentation -Visual C+Documentation -Using Visual C+-Visual C+Programmers Guide -Run-Time Library Reference -Run Time Routines by Category -Run Time Routines by Category 使用C+系统函数76第76页 前一页 休息作作 业业l复习第三章,预习第四章复习第三章,预习第四章l3-2,3-8,3-11,3-13,3-15l学习使用联机帮助系统查找系统函数学习使用联机帮助系统查找系统函数l试验三试验三77第77页