C+程序设计语言揣锦华第2章函数.ppt



《C+程序设计语言揣锦华第2章函数.ppt》由会员分享,可在线阅读,更多相关《C+程序设计语言揣锦华第2章函数.ppt(97页珍藏版)》请在装配图网上搜索。
1、第2章 函 数,2.1 函数的定义与使用 2.2 函数调用机制 2.3 递归函数 2.4 默认参数的函数 2.5 内联函数 2.6 函数重载 2.7 函数模板 2.8 使用C++系统函数,2.1 函数的定义与使用,在编辑一个大型程序时,即使各个函数的前后顺序不同,程序执行的开始点永远是主函数。主函数按照调用与被调用关系调用子函数。子函数如果与其它子函数又存在调用与被调用关系,当然还可以再调用其它子函数。,在一对调用与被调用关系中,我们把调用其它函数的函数称为主调函数,被其它函数调用的函数称为被调函数。在一个较为复杂的大型程序中,一个函数很可能同时扮演两种不同的角色主调函数与被调函数,即既调用别
2、的函数(被调函数)又被另外的函数(主调函数)调用。函数一般应遵守先定义后调用的原则,否则应在调用函数中先进行原形说明。,2.1.1 函数的定义 一个完整的函数定义由两部分组成,即函数头与函数体。 1. 函数定义的一般语法形式 (形式参数表) 说明性语句序列; 实现函数功能的语句系列; ,函数头是指上述格式中的 (形式参数表)。其中函数名可由函数设计者命名,可以是任何一个不重复的合法的标识符(唯一的例外是,主函数必须命名为main)。 函数体是指上述格式中被一对大括号括起的复合语句部分。该函数所应实现的功能由相应的复合语句完成。,2. 函数的类型和返回值 函数头部分的类型标识符规定
3、了函数的返回值类型。函数的返回值是返回给主调函数的处理结果,由函数体部分的return语句带回。例如,return value1。 无返回值的函数其类型标识符为void,不必有return语句。,3. 形式参数 函数头部分的形式参数(简称形参)表的内容如下:类型l 形参名1,类型2 形参名2,...,类型n 形参名n其中类型1、类型2、...、类型n是类型标识符,表示形参的数据类型(int、double、float、char、bool等);形参名1、形参名2、...、形参名n是形参名(合法的自定义标识符)。形参是用来实现主调函数与被调函数之间的数据联系,通常将函数所处理的数据、影响函
4、数功能的因素或者函数处理的结果作为形参。对于无形参的函数,其形参表的内容应该为空,但代表函数的小括号对不能省略。,函数在没有被调用的时候其形参只是一个符号,它标志着在形参出现的位置应该有一个什么类型的数据。函数在被调用时才由主调函数将实际参数(简称实参)赋予形参。从这一点上说,C++中的函数与数学中的函数概念极其相似。例如,我们都熟悉的如下数学中的函数形式: f(x)=3x2+5x-2 这个函数只有当自变量x被赋以确定的值以后,才能计算出函数的值。,2.1.2 函数的调用 如果没有遵守先定义后调用的原则,调用函数之前先要在主调函数中声明函数原型。在主调函数中,或所有
5、函数之前,按如下形式进行函数原型声明: (含类型说明的形参表);,如果是在所有函数之前声明了函数原型,那么该函数原型在本程序文件中任何地方都有效,也就是说,在本程序文件中任何地方都可以依照该原型调用相应的函数。如果是在某个主调函数内部声明了被调函数原型,那么该原型就只能在这个函数内部有效。 声明了函数原型之后,便可以按如下形式调用子函数: (实参1,实参2,,实参n),实参列表中应给出与函数原型中形参个数相同、类型相符的实参,每个实参都可以是常量、变量或表达式三者之一。实参与实参之间用逗号作为分隔符。注意,这里的逗号不是顺序求值运算符。函数调用可以作为一条语句,这时函数可以没
6、有返回值。函数调用也可以出现在表达式中,这时就必须有一个明确的返回值。函数调用示例如下。,【例2-1】 编写一个函数,把华氏温度转换为摄氏温度,公式为C=(F-32)*5/9,公式中F代表华氏温度,C代表摄氏温度。在主函数中提示用户输入一个华氏温度,并完成输入及输出,由函数完成转化功能。 程序代码如下: #include float hstoss(float fHuashi);//原型说明 void main( ) ,float fHuashi; coutfHuashi; cout<<华氏< 7、uashi)<<度< 8、 < 9、数,只要将二进制数的每一位乘以该位的权,然后相加。例如,110100112=1(27)1(26)0(25)1(24)0(23)0(22)1(21)l(20)=21110,所以,如果输入00001101,则应输出13。,可以直接引用例2-2中的函数power来求2的各次方。 程序代码如下: #include double power(double dDishu,int iMi);//函数原型说明 void main( ) int iCount=8; int iValue=0; char cChar; bool bFlag=true;,cout0) cincChar; if(cChar!=1,iC 10、ount--; if(bFlag) cout<<十进制值为:< 11、进制数:110lao11 这不是一个二进制数! 不能正确转换,【例2-4】 编写一个函数可用来判断任给的一个正整数是否为素数(或质数)。再编写主程序完成输入、调用和输出。素数是指只能被1和它自身整除的数。 分析:素数的逆定义就是,一但某数n能被2、3、...、n-1中的任何一个数除尽(只要除法中有一次余数为零),则n肯定不是一个素数;某数n若依次除以2、3、...、n-1,结果都除不尽(有余数),则n肯定是一个素数。,程序代码如下: #include int iIsprime(int iNum); void main( ) int iNum; coutiNum; if(iIspri 12、me(iNum)==1) cout< 13、正整数:119 119不是一个素数,2.1.3 函数的参数传递 函数的参数用于在调用函数与被调用函数之间进行数据传递。在函数定义时,函数名后面括号内的参数称为形式参数(简称形参)。在函数被调用时,函数名后面括号内的参数称为实际参数(简称实参)。,当函数未被调用时,C++编译系统并没有给函数的形参分配相应的内存空间,函数的形参更不会有实际的值。只有在函数被调用时,C++编译系统这时才为形参分配实际的存储单元,并将实参与形参结合。实参可以是常量、变量或表达式,其类型必须与形参相符。函数的参数传递,指的就是形参与实参结合(简称形实结合)的过程。形实结合的方式有值调用和引用调用两种。,1. 值调 14、用 值调用是指当发生函数调用时,编译系统为形参分配相应的存储空间并且直接将实参的值复制给形参,这样形参和实参就各自拥有不同的存储单元,且形参是实参的副本。因此,值调用过程是参数值的单向传递过程,一旦形参获得了与实参相同的值就与实参脱离关系,以后不论形参发生多大的改变,都决不会反过来影响到实参。前面2.1.2节中的四道例题均属于值调用方式。,【例2-5】 从键盘输入两个整数,交换位置后输出(交换未成功)。 #include void swap(int a,int b); void main( ) int x,y; x=5; y=10; cout< 15、swap(x,y); //交换x,y的值,cout< 16、参y中的值10传递给虚参b;在swap函数中,a、b中的值完成互换;返回主函数时,实参x、y中的值不受虚参a、b的影响,并未进行交换。,2. 引用调用 显而易见,值调用时参数的传递方式是实参单向复制其值给虚参,如果我们想使子函数中对形参所做的任何更改也能及时反映给主函数中的实参(即希望形参与实参的影响是互相的或称是双向的),又该怎么办呢?这就需要改变调用方式,即采用第二种参数传递方式引用调用。 引用是一种特殊类型的变量,可以被认为是某一个变量的别名。通过引用名与通过被引用的变量名访问变量的效果是一样的。这就是说,对形参的任何操作也就直接作用于实参。,例如: int a,b; 17、 int 注意: 声明一个引用时,必须同时对它进行初始化,使它与一个已存在的对象关联。, 一旦一个引用被初始化后,就不能改变关联对象。换言之,一个引用从它被声明之后,就必须确定是哪个变量的别名,而且自始至终只能作为这一个变量的别名,不能另作他用。 形参也可以引用的方式出现在形参表中。引用作为形参的情况与变量的引用稍有不同。这是因为,形参的初始化不在类型说明时进行,而是在执行主调函数中的调用语句时,才为形参分配内存空间,同时用实参来初始化形参。,【例2-6】 使用引用调用改写例2-5的程序,使两实参中的数真正进行互换。 #include void swap(int , void 18、 swap(int 程序运行结果为 x=5 y=10 after swap x=10 y=5,分析:子函数swap的两个参数都是引用,当被调用时,它们分别被初始化成为a和b的别名。因此,在子函数swap中将两个参数的值进行交换后,交换结果可以返回主函数main。,2.2 函数调用机制,一个C++的源程序经过编译以后形成与源程序主名相同但后缀为.exe的可执行文件,且存放在外存储器中。当该 .exe的可执行程序被运行时,首先从外存将程序代码装载到内存的代码区,然后从main函数的起始处开始执行。程序在执行过程中,如果遇到了对其它函数的调用,则暂停当前函数的执行,,保存下一条指令的地址(即返回地址 19、,作为从子函数返回后继续执行的入口点),并保存现场(主要是一些寄存器的内容),然后转到子函数的入口地址,执行子函数。当遇到return语句或者子函数结束时,则恢复先前保存的现场,并从先前保存的返回地址开始继续执行。图2-1说明了函数调用和返回的过程,图中标号标明了执行顺序。,图2-1 函数调用和返回的示意图,【例2-7】 求 设N=10,X=2、4、6、8,即求N事件中每次取2、4、6、8的组合数。 分析:这个问题需要反复利用两个公式: N! N!/X!/(N-X)! 设计两个函数:一个求整数阶乘的函数lJiecheng和一个求组合数的函数lComb。由主函数m 20、ain调用lComb,lComb又调用lJiecheng。,程序代码如下: #include long lJiecheng(int n) long rt=1; int i; for(i=1;i<=n;i++) rt=rt*i; return rt; long lComb(int N,int X), return lJiecheng(N)/lJiecheng(X)/lJiecheng(N-X); void main( ) long lJiecheng(int n); long lComb(int N,int X); int iNum,x; do ,coutiNum; while(iNum<10) 21、; for(x=2;x<10;x+=2) cout< 22、... ,所谓间接调用自身,就是一个函数func1调用另一个函数func2,而函数func2中又调用了函数func1,于是构成间接递归。下面的例子属于间接调用情况。 void func1(void) ... func2( ); //func1调用func2 ... void func2(void) ,... func1( ); //func2调用func1 ... func1函数就是通过func2实现间接递归。 递归算法的实质是将原有的问题分解为新的问题,而解决新问题时又用到了原有问题的解法。按照这 23、一原则分解下去,每次出现的新问题都是原有问题的简化的子集,而最终分解出来的问题,是一个已知解的问题。这便是有限的递归调用。,【例2-8】编写函数,用递归的方法求n!的值。在主程序中实现任意输入n值并输出计算结果。 分析:计算n!的公式如下。 1(n=0) n!= n(n-1)! (n0) 这是一个递归形式的公式,在描述阶乘算法时,又用到了阶乘,只不过求阶乘的数在逐次减1,因而编程时也自然采用递归算法。递归的结束条件是n=0。,程序代码如下: #include long jc(int n) long rt; if(n<0) cout<
24、dl; else if(n==0) rt=1;//递归的结束条件 else rt=n*jc(n-1);//以参数减1的方式继续递归 return rt;, void main( ) long jc(int n); int n; long result; do coutn; while(n<=0);,result=jc(n);//首次调用处 cout< 25、第4个人多少岁,他说比第5个人大2岁。最后问第5个人,他说是12岁。请问第1个人多少岁? 分析:这是一个递归问题。每一个人的年龄都比其后那个人的年龄大2,即,age(1)=age(2)+2 age(2)=age(3)+2 age(3)=age(4)+2 age(4)=age(5)+2 age(5)=12 可以用公式表示如下: 12(n=5) age(n)= age(n+1)+2 (n<5),程序代码如下: #include int age(int n) int ss; if(n==5)ss=12; elsess=age(n+1)+2; return(ss); void main( ), i 26、nt age(int n); cout<<第一个人的年龄为< 27、)//第二个形参具有默认值 if(k==2) return (n*n); else return (mult(n,k-1)*n); void main( ), cout< 28、k)//非法 void try(int j,int k=2,int m)//非法 void try(int j,int k=7)//合法 void try(int j,int k=2,int m=3) //合法 void try(int j=3,int k=2,int m=3)//合法,默认形参值应该在函数原型中给出。例如: int multi(int x=2,int y=5);//默认形参值在函数原型中给出 void main( ) multi( );//并非无参调用,而是采用默认值,x取值2,y取值5 int multi(int x,int y) return(x*y); ,在相同的作 29、用域内,默认形参值的说明应保持唯一。但如果在不同的作用域内,允许说明不同的默认形参。这里的作用域是指直接包含着函数原型说明的大括号所界定的范围。对作用域概念的详细介绍请参阅第5章。例如: int add(int x=2,int y=5); //全局默认形参值 void main( ) int add(int x=1,int y=9); //局部默认形参值,add( ); //此处调用时,采用局部默认形参值,x取值1,y取值9 void func(void) add( ) //此处调用时,采用全局默认形参值,x取值2,y取值5 ,2.5 内 联 函 数,内联函数(也称在 30、线函数)是在C++中为提高程序运行效率而引入的。所有函数调用时都会产生一些额外的开销,主要是系统栈的保护、代码的传递、系统栈的恢复以及参数传递等。对于一些函数体很小但又经常使用的函数,由于被调用的频率非常高,这种额外开销也就很可观,有时甚至会对运行效率产生本质的影响。,使用内联函数正是解决这一问题的手段。 内联函数不是在调用时发生转移,而是在编译时将函数体嵌入在每一个调用语句处。这样就相对节省了参数传递、系统栈的保护与恢复等的开销。 内联函数在定义时使用关键字inline区别于一般函数,其语法形式如下: (含类型说明的形参表) 函数体 ,例如: 31、inline int mul(int a,int b) return a*b; 当程序中出现mul(2+3,4)的函数调用时,编译程序就会将其扩展为(2+3)*4。关键字inline是一个编译命令,编译程序在遇到这个命令时将记录下来,在处理内联函数的调用时,编译程序就试图产生扩展码。这样从使用者的角度来看,内联函数在语法上与一般函数没有什么区别,只是在编译程序生成目标代码时才区别处理。,注意: 内联函数体内一般不能有循环语句和switch语句。 内联函数的定义必须出现在第一次被调用之前。 对内联函数不能进行异常接口声明。 如果违背了上述注意事 32、项中的任一项,编译程序就会无视关键字inline的存在,像处理一般函数一样处理,不生成扩展代码。因此,只有很简单而使用频率很高的函数才被说明为内联函数。内联函数会扩大目标代码,使用时要谨慎。,【例2-11】内联函数例题。 #include #include inline int max(int a,int b) if(ab) return a; else return b; ,void main( ) int a,b,c,d; a=210; b=150; c=20; d=max(a,b); d=max(d,c); //编译时两个调用处均被替换为max函数体语句。 cout< 33、st of < 34、义求平方函数,就必须对整数的平方、浮点数的平方以及双精度数的平方分别用不同的函数名: intisq(int x,int y); float fsq(float x,float y); double dsq(double x,double y);,程序在调用这三个不同类型的函数时,是以名字加以区别的,需要记住并区别它们的名称。显然,这样就造成了代码的重复,使用起来也不方便,更不利于代码的维护。 对于具有重载机制的C++语言,允许功能相近的函数在相同的作用域内以相同函数名定义,因而使函数方便使用,便于记忆,也使程序设计更加灵活。仍以上例而言,在C++中只要用一个函数名 35、即可,如square( ),然后以赋给此函数的参数类型来决定是要计算int型、float型,还是double型的数的平方。上例在C++中的定义形式如下:,int square(int x); float square(float x); double square(double x); 要计算square(3)时,C++自动使用第一种形式;计算square(3.25)时,C++自动使用第三种形式;计算square(3.25f)时,C++自动使用第二种形式。 但是决不可以定义两个具有相同名称、相同参数类型和相同参数个数,只是函数返回值不同的重载函数。,例如,以下定义是C+ 36、+不允许的: int func(int x); float func(int x); 由此可见,C++是按函数的参数表分辨相同名称的函数。如果参数表相同,则认为是错误的说明。 C++允许重载函数有数量不同的参数个数。当函数名相同而参数个数不同时,C++会自动按参数个数定向到正确的要调用的函数。下例说明了C++的这一特性。,【例2-12】重载函数应用例题。 #include int add(int x,int y) int sum; sum=x+y; return(sum); int add(int x,int y,int z) ,int sum; sum=x+y+z
- 温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 化妆品美妆产品介绍自然之选清新护肤
- 心理健康情绪管理主题班会我的情绪小怪兽
- 慢性病宣传慢性肾脏病防治如何预防和管理慢性肾脏病
- 深入学习2025最高人民法院工作报告
- 孩子如何合理使用DeepSeek(AI仅辅助不可让渡创造力)
- 肝病健康知识宣讲甲型肝炎及戊型肝炎传播和预防
- 慢性肾脏病知识宣传慢性肾脏病的危害
- 315消费者权益日共筑满意消费
- 世界睡眠日健康睡眠知识科普睡眠是维持生命健康的重要源泉
- 深入学习2025政府工作报告要点双语版
- 初中语文作文素材:100个描写外貌佳句
- 初中语文古诗词鉴常考题型及答题技巧
- 初中语文作文素材:9个落笔即封神的议论文作文论据
- 初中资料:学好语文的方法及技巧
- 初中语文作文素材:经典格言总结