




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、1问题1 1,为什么要用函数,为什么要用函数2 2,使用函数的程序和顺序程序有什,使用函数的程序和顺序程序有什么区别?么区别?第1页/共106页25.3.15.3.1函数的嵌套函数的嵌套函数的嵌套一个函数的函数体中包含一个或多个函数调用语句,即称为函数一个函数的函数体中包含一个或多个函数调用语句,即称为函数嵌套嵌套 。 嵌套的含义是,如果函数A 要调用函数B,也就是说,函数A 的定义要依赖于函数B 的定义。因此函数B 的定义或函数B 的原型必须出现在函数A 的定义语句之前。 另一方面,函数A 调用函数B,在调用A 的过程中,即执行A 的函数体过程中,调用B,也就是中途把程序控制转到B 的函数体
2、,在执行结束后再返回到A 的函数体中。 函数嵌套调用所占用的空间(如赋值参数的创建等等)用堆栈(stack)的方式管理。一般这种堆栈所分配的空间是有限的,因此函数互相嵌套的层数也是有限的,依编译系统不同,其允许的嵌套层数也可能不同。 第2页/共106页3 函数调用的堆栈情况堆栈Main()cuberoot( x ) 参数传递、返回值保护现场、恢复现场调用返回第3页/共106页4实例# include void f1 (int,int); void f2 (int); void main () int a, b ; cout a ; cout b; f1 (a, a+b); cout endl
3、a+b endl; void f1 (int x, int y) int m = 2; x *= m ;y+; f2 (x+y)/m);void f2 (int p) if (p = 100) cout endl 1n1时,时, n!=nn!=n* *(n-1)!(n-1)!这正是我们编写求这正是我们编写求n n的阶乘的递归函数的阶乘的递归函数prodprod的基础。的基础。第8页/共106页9#include #include long prod(int n) /long prod(int n) /注意用的是注意用的是longlong,课本课本p131p131(3 3) if ( n=1 )
4、 if ( n=1 ) return 1; /nreturn 1; /n等于等于1 1时,递归出口时,递归出口( (“退出退出”递归递归) ) else elsereturn n return n * * prod(n-1)prod(n-1); ; / n/ n大于大于1 1时的返回值时的返回值( (n!)n!)为为n n乘以乘以n-1n-1的阶乘的阶乘/ ( / ( 使用自递归调用使用自递归调用“prod(n-1)prod(n-1)”来求出来求出( (n-1)! )n-1)! )第9页/共106页10void main( ) void main( ) int n; int n; coutIn
5、put a positive integer:; coutn; cinn; / /输入的正整数放入输入的正整数放入n n中中 long p=prod(n); /long p=prod(n); /求出求出n n的阶乘放入的阶乘放入p p中中 coutp=1coutp=1* *.* *n=pendl; n=pendl; /输出结果输出结果p p 第10页/共106页11 上 述 求 阶 乘 的 递 归 函 数 中 , 当 主 函 数 通 过上 述 求 阶 乘 的 递 归 函 数 中 , 当 主 函 数 通 过prod(3)prod(3)对递归函数对递归函数prodprod进行调用时,它的返回值进行
6、调用时,它的返回值为为3 3* *prod(2)prod(2),此时系统将再一次对此时系统将再一次对prodprod本身进行本身进行调用而形成递归调用。调用而形成递归调用。 但注意后一次调用的实参为但注意后一次调用的实参为2 2,比上一次的实,比上一次的实参参3 3“下降下降”了了1 1。而计算。而计算prod(2)prod(2)时,它的返回值时,它的返回值为为2 2* *prod(1)prod(1),此时系统将再一次对此时系统将再一次对prodprod本身进行本身进行递归调用,但此时的实参又递归调用,但此时的实参又“下降下降”了了1 1。第11页/共106页12 正是通过这种实参的逐次正是通
7、过这种实参的逐次“下降下降”,可保障,可保障递归函数在执行若干次后递归函数在执行若干次后( (此时的求阶乘问题当此时的求阶乘问题当“下降下降”到到1 1时时) ),能够,能够“退出退出”递归递归( (不再进行不再进行递归调用,也即实现了递归出口递归调用,也即实现了递归出口) )。 由于由于prod(1)prod(1)的返回的返回值为值为1 1,系统进一步算,系统进一步算出出2 2* *prod(1)prod(1)的值(即的值(即prod(2)prod(2)的值)为的值)为2 2* *1=21=2,再进一步算出再进一步算出3 3* *prod(2)prod(2)的值为的值为3 3* *2=62=
8、6,这正是,这正是prod(3)prod(3)的调用返回值的调用返回值( (也即求出了也即求出了3!=33!=3* *2 2* *1=6)1=6)。 第12页/共106页13 虽然上述执行过程是由系统自动完成的,虽然上述执行过程是由系统自动完成的,但程序员要理解并熟知这种调用机制与系统实现但程序员要理解并熟知这种调用机制与系统实现方法,从而才能编写出逻辑正确且简明易懂的递方法,从而才能编写出逻辑正确且简明易懂的递归处理程序。归处理程序。 另外注意,递归处理程序的执行速度通常另外注意,递归处理程序的执行速度通常要比非递归处理方法慢。要比非递归处理方法慢。问题:为什么会慢?问题:为什么会慢? 第1
9、3页/共106页14 求出1 1到n n之累加和的递归函数sumsum 使程序执行后的输出结果为使程序执行后的输出结果为: :Input a positive integer:Input a positive integer:100100s=1+.+100=5050s=1+.+100=5050第14页/共106页15# #include include int sum(int n) int sum(int n) /递归函数递归函数sumsum if ( n=1 ) if ( n=1 ) /n/n等于等于1 1时,递归出口时,递归出口return 1;return 1; else else re
10、turn n + return n + sum(n-1)sum(n-1); ; /n/n大于大于1 1时的返回值时的返回值( (累加和累加和) )为为n n加上加上“从从1 1累加到累加到/n-1/n-1的和的和”( (要使用要使用递归调用递归调用求出前求出前n-1n-1个数的累个数的累加和加和) )第15页/共106页16 void main( ) void main( ) int n; int n; coutInput a positive integer:; coutn; cinn; int s=sum(n); /int s=sum(n); /求出从求出从1 1累加到累加到n n的和放的
11、和放s s中中 couts=1+.+n=sendl; couts=1+.+n=sendl; 第16页/共106页172 2 反序输出从键盘输入的反序输出从键盘输入的1010个整数个整数 反序输出:从键盘输入反序输出:从键盘输入10 10 个个int int 型数,型数,而后按输入的相反顺序输出它们。而后按输入的相反顺序输出它们。例如:例如:输入:输入:1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 输出:输出:10 9 8 7 6 5 4 3 2 110 9 8 7 6 5 4 3 2 1第17页/共106页18 2 2 反序输出从键盘输入的反序输出从键盘输
12、入的1010个整数个整数#includevoidinv(intn)inti;cini;/输入if(n1)inv(n-1);/递归elsecout“-Theresult-”endl;/递归出口couti“”;/输出void main(void) coutInput 10 integers:endl;inv(10); coutendl; 第18页/共106页19 2 2 反序输出从键盘输入的反序输出从键盘输入的1010个整数个整数 可以有下面的执行结果:可以有下面的执行结果: Input 10 integers:Input 10 integers:1 2 3 4 5 6 7 8 9 101 2 3
13、 4 5 6 7 8 9 10- The result - The result -10 9 8 7 6 5 4 3 2 110 9 8 7 6 5 4 3 2 1第19页/共106页20 3 3 反序输出一个整数反序输出一个整数 在许多情形下递归函数易写易读,像解著在许多情形下递归函数易写易读,像解著名的名的Hanoi Hanoi 塔问题的递归函数,其递归程塔问题的递归函数,其递归程序很短,也极易理解序很短,也极易理解( (见见5.6 5.6 节节) ),但是,但是,如果不用递归方法,程序将十分复杂,很如果不用递归方法,程序将十分复杂,很难编写。难编写。要求要求 反序输出一个正整数的各位数值
14、,反序输出一个正整数的各位数值, 如输入如输入231231,应输出,应输出132132。 第20页/共106页21 3 3 反序输出一个整数反序输出一个整数#includeintconv(intn)if(n10)coutn;return;/递归出口coutn%10;conve(n/10);/递归 void main(void) int t;cout t; cout endl; conv(t);第21页/共106页22 3 3 反序输出一个整数反序输出一个整数输出结果为:Input a positive number: 47811874如果不用递归函数设计,程序不如递归形式清晰: int con
15、v(int n) if (n0) cout “Please input a positive number!”;else do cout n%10;n=/10; while (n!=0); 第22页/共106页23 总结(1) (1) 无论是直接递归还是间接递归都必须保证在无论是直接递归还是间接递归都必须保证在有限次调用之后能够结束。例如函数有限次调用之后能够结束。例如函数fac fac 中中的参数的参数n n 在递归调用中每次减在递归调用中每次减1 1,总可达到,总可达到2 2 的状态而结束。的状态而结束。(2) (2) 函数调用时系统要付出时间和空间代价,在函数调用时系统要付出时间和空间代
16、价,在环境条件相同的情形下,总是非递归程序效环境条件相同的情形下,总是非递归程序效率较高。率较高。 第23页/共106页24 5.4 5.4 函数和运算符的重载5.4.1 5.4.1 函数重载函数重载5.4.2 5.4.2 可重载运算符可重载运算符5.4.3 5.4.3 运算符重载函数的定义运算符重载函数的定义第24页/共106页25 5.4.1 5.4.1 函数的重载 函数重载实际上是函数名重载,即支持多个不同的函数采用函数重载实际上是函数名重载,即支持多个不同的函数采用同一名字。同一名字。 例如:例如: int absint abs(int nint n)returnreturn(n n0
17、 0?-n-n:n n; float abs float abs(float ffloat f)ifif(f f0 0)f f-f-f; return freturn f; double abs double abs(double ddouble d)ifif(d d0 0)return-dreturn-d;return return d d; 三个函数都是求绝对值,采用同一个函数名,更符合人们的习三个函数都是求绝对值,采用同一个函数名,更符合人们的习惯惯 . .例如在程序中经常出现这样的情况:对若干种不同的数据类型例如在程序中经常出现这样的情况:对若干种不同的数据类型求和,虽然数据本身差别很
18、大(例如整数求和,向量求和,求和,虽然数据本身差别很大(例如整数求和,向量求和,矩阵求和),具体的求和操作差别也很大,但完成不同求和矩阵求和),具体的求和操作差别也很大,但完成不同求和操作的函数却可以取相同的名字(例如操作的函数却可以取相同的名字(例如sumsum,add add 等)。打等)。打印函数印函数printprint,显示函数,显示函数displaydisplay等也是同样。等也是同样。 第25页/共106页26 5.4.1 5.4.1 函数的重载 函数名的重载并不是为了节省标识符(标识符的数量是足够的),而是为了方便函数名的重载并不是为了节省标识符(标识符的数量是足够的),而是为
19、了方便程序员的使用,这一点很重要。实现函数的重载必须满足下列条件之一:程序员的使用,这一点很重要。实现函数的重载必须满足下列条件之一: (1 1)参数表中对应的参数类型不同;)参数表中对应的参数类型不同; (2 2)参数表中参数个数不同;)参数表中参数个数不同; (3 3)参数表中不同类型参数的次序不同。)参数表中不同类型参数的次序不同。第26页/共106页27 5.4.1 5.4.1 函数的重载例如:例如: void printvoid print(intint);); /整型整型 void print void print(pointpoint);); /类类point point 的对象
20、的对象 int sumint sum(int int ,intint);); int sum int sum(int int ,int int ,intint);); int get int get(int nint n,float a float a );); int get int get(int nint n,float a float a ,int nint n);); 第27页/共106页28 5.4.1 5.4.1 函数的重载在定义同名函数时应注意:在定义同名函数时应注意: (1 1)返回类型不能区分函数,)返回类型不能区分函数, float addfloat add(int fl
21、oatint float);); int addint add(int floatint float););/错误错误 (2 2)采用引用参数不能区分函数,)采用引用参数不能区分函数,void printvoid print(doubledouble);); void printvoid print(doubledouble); /); /错误错误 (3 3)有些派生基本类型的参数虽然可以区分同名函数,)有些派生基本类型的参数虽然可以区分同名函数,但在使用中必须注意但在使用中必须注意 (4 4)包含可缺省参数时,可能造成二义性,)包含可缺省参数时,可能造成二义性, 第28页/共106页29 5
22、.4.1 5.4.1 函数的重载C+C+对函数重载的处理过程:对函数重载的处理过程:(1 1)通过数组名与指针变量,函数名与函数指针,某类)通过数组名与指针变量,函数名与函数指针,某类型变量与型变量与const const 常量之间的转换,再查是否可实现常量之间的转换,再查是否可实现匹配;匹配;(2 2)把实参类型从低到高(按字长由短到长)进行基本)把实参类型从低到高(按字长由短到长)进行基本类型及其派生类型的转换,再检查是否可匹配;类型及其派生类型的转换,再检查是否可匹配; (3 3)查有无已定义的可变个数参数的函数,如有把它归)查有无已定义的可变个数参数的函数,如有把它归为该函数。为该函数
23、。在进行上述尝试性的处理之后可能出现仍无匹配或匹配在进行上述尝试性的处理之后可能出现仍无匹配或匹配不唯一的情况,这时可能输出出错信息或错误地运行。不唯一的情况,这时可能输出出错信息或错误地运行。 第29页/共106页30 5.4.2 5.4.2 可重载运算符C+C+语言中的运算符实际上是函数的方便表示形式,语言中的运算符实际上是函数的方便表示形式,例如,算术运算符例如,算术运算符”+ +” 也可以表示为函数形式:也可以表示为函数形式:int add (int a, int b) return a+b; int add (int a, int b) return a+b; 这时,这时,a+b a
24、+b 和和 add (a,b) add (a,b) 的含义是一样的。的含义是一样的。 C+C+语言规定,大多数运算符都可以重载,语言规定,大多数运算符都可以重载,单目运算符:单目运算符:- -, ,!,!,+,-,newnew,deletedelete双目运算符:双目运算符: + +,- -,* *, , , , = =,!=!=, ,=- ,= = , , 等等 第30页/共106页31 5.4.2 5.4.2 可重载运算符(1 1)可重载运算符几乎包含了)可重载运算符几乎包含了C+C+的全部运算符集,例外的是:限的全部运算符集,例外的是:限定符定符. .,:,条件运算符?:,取长度运算符,
25、:,条件运算符?:,取长度运算符sizeof sizeof 它们不它们不可重载可重载 (2 2)在可重载的运算符中有几种不同情况:)在可重载的运算符中有几种不同情况: 算术运算符,逻辑运算符,位运算符等与基本数据类型有关,通算术运算符,逻辑运算符,位运算符等与基本数据类型有关,通过运算苻重载函数的定义,使它们可以用于某些用户定义的数过运算苻重载函数的定义,使它们可以用于某些用户定义的数据类型,这是重载的主要目的。据类型,这是重载的主要目的。赋值运算符,关系运算符,!等所涉及的数据类型按赋值运算符,关系运算符,!等所涉及的数据类型按C+C+程序规定,并非只限于基本数值类型。因此,这些运算符程序规
26、定,并非只限于基本数值类型。因此,这些运算符可以自动地扩展到任何用户定义的数据类型,一般不需作重载可以自动地扩展到任何用户定义的数据类型,一般不需作重载定义就可定义就可“自动自动”地实现重载。地实现重载。 单目运算符单目运算符+和和-实际上各有两种用法,前缀增(减)量和后缀实际上各有两种用法,前缀增(减)量和后缀增(减)量。其运算符重载函数的定义当然是不同的,对两种增(减)量。其运算符重载函数的定义当然是不同的,对两种不同的运算无法从重载函数的原型上予以区分:函数名不同的运算无法从重载函数的原型上予以区分:函数名(operator +operator +)和参数表完全一样。为了区别前缀)和参数
27、表完全一样。为了区别前缀+和后缀和后缀+,C+C+语言规定,在后缀语言规定,在后缀+的重载函数的原型参数表中增加的重载函数的原型参数表中增加一个一个int int 型的无名参数。型的无名参数。 第31页/共106页32 5.4.3 5.4.3 运算符重载函数的定义 运算符的重载是一个特殊函数定义过程,这运算符的重载是一个特殊函数定义过程,这类函数总是以类函数总是以operatoroperator 作为函数名。作为函数名。其实例在第七章以后引进其实例在第七章以后引进 假设程序中定义了一个枚举类型的bool 类型: enum boolFALSE,TRUE; 用运算符(双目),*(双目),(单目)来
28、表示或、与、非运算是十分方便的:第32页/共106页33 5.4.3 5.4.3 运算符重载函数的定义booloperator+(boola,boolb)if(aFALSE)(bFALSE)returnFALSE;returnTRUE;booloperator*(boola,boolb)if(aTRUE)(bTRUE)returnTRUE;returnFALSE;booloperator-(boola)if(aFALSE)returnTRUE;returnFALSE;我们可以在程序中方便的表示其运算:我们可以在程序中方便的表示其运算: b1b1b1+b2b1+b2; b1b1-b3-b3; b
29、1b1(b1+b3b1+b3)* * FALSEFALSE;第33页/共106页34 5.4.3 5.4.3 运算符重载函数的定义运算符重载函数的调用可有两种方式:运算符重载函数的调用可有两种方式:1 1 与原运算符相同的调用方式,如上例中的与原运算符相同的调用方式,如上例中的b1+b2b1+b2,b1b1* *b2b2,等等。,等等。2 2 一般函数调用方式,如一般函数调用方式,如b1+b2b1+b2,也可以写为,也可以写为operator+operator+(b1b1,b2b2)被重载的运算符的调用方式,)被重载的运算符的调用方式,优先级和运算顺序都与原运算符一致,其运算分量优先级和运算顺
30、序都与原运算符一致,其运算分量的个数也不可改变。的个数也不可改变。3 3 运算符重载主要用于用类的形式定义的用户定义运算符重载主要用于用类的形式定义的用户定义类型,例如,复数类型,集合类型,向量类型等等,类型,例如,复数类型,集合类型,向量类型等等,通过运算符重载把人们习惯的运算符引入到计算操通过运算符重载把人们习惯的运算符引入到计算操作之中,会收到很好的效果。这样的实例将在第七作之中,会收到很好的效果。这样的实例将在第七章介绍。章介绍。 第34页/共106页35 5.5 5.5 函数与C+C+程序结构5.5.15.5.1库函数的使用库函数的使用 库函数又称标准函数,是库函数又称标准函数,是C
31、+C+语言编译系统语言编译系统为用户提供的内部函数,其编写与一般用户为用户提供的内部函数,其编写与一般用户定义的函数相同,程序员可在程序中直接使定义的函数相同,程序员可在程序中直接使用,但是要在程序开头说明库函数所在的头用,但是要在程序开头说明库函数所在的头文件名,例如:文件名,例如: #include #include #include #include C+系统中有一个很大的标准函数库(和标准类库),包括许多在各种程序中常用的基本任务处理函数,这些库函数被分成不同的组,例如,数学计算、字符处理、字符串处理、I/O操作、图形处理等等, 第35页/共106页36 5.5.2 SP5.5.2 S
32、P框架结构 按结构程序设计(按结构程序设计(SPSP)思想设计的程序结构称为)思想设计的程序结构称为SPSP框架。函数是框架。函数是SPSP框架的核心。框架的核心。 一个一个SPSP框架的完整框架的完整C+C+程序由下面几部分组成:程序由下面几部分组成:1 1)一个主函数。它可调用其它函数,但不能被调)一个主函数。它可调用其它函数,但不能被调用。用。2 2)任意多个用户定义函数。都处于同一)任意多个用户定义函数。都处于同一“等级等级”,可以互相调用。可以互相调用。3 3)全局说明。在所有函数定义之外的变量说明和)全局说明。在所有函数定义之外的变量说明和函数原型。函数原型。4 4)预处理命令。在
33、进行预处理后,这部分被取代。)预处理命令。在进行预处理后,这部分被取代。5 5)注释。只起方便阅读的作用,编译后被删除。)注释。只起方便阅读的作用,编译后被删除。第36页/共106页37 5.5.2 SP5.5.2 SP框架结构 对于比较大的程序,可以把它们划分为几个程序文对于比较大的程序,可以把它们划分为几个程序文件,这些程序模块可能由一个或多个程序员编写,件,这些程序模块可能由一个或多个程序员编写,最简单而有效的划分方法是:最简单而有效的划分方法是: 根据主函数和各用户定义的函数的功能及相互根据主函数和各用户定义的函数的功能及相互关系,把它们划分成若干个关系,把它们划分成若干个.CPP.C
34、PP文件。文件。 按与每个按与每个.CPP .CPP 程序文件中的函数有关的全局程序文件中的函数有关的全局说明组成一个或多个说明组成一个或多个.h.h(头)文件。(头)文件。 程序中使用的库函数组成的若干程序中使用的库函数组成的若干.CPP .CPP 文件和文件和对应的对应的.h .h 文件。在预处理命令的帮助下,一个文件。在预处理命令的帮助下,一个C+C+程序被划分为若干程序被划分为若干.CPP.CPP和和.h.h程序文件。在包含命令程序文件。在包含命令的帮助下,这些文件形成了一个有机的整体。的帮助下,这些文件形成了一个有机的整体。在这样的模块结构中,各个在这样的模块结构中,各个.CPP.C
35、PP文件是全部函数的文件是全部函数的划分,它们组成了程序代码的主体。划分,它们组成了程序代码的主体。第37页/共106页38 5.5.5.3 5.3 函数间的数据传递 1. 1. 通过赋值参数和返回语句(单向)通过赋值参数和返回语句(单向) 2 2通过全局变量(双向)通过全局变量(双向) 3.3.通过指针类型参数和引用参数(双向)通过指针类型参数和引用参数(双向) 4.4.函数的数组类型参数(双向)函数的数组类型参数(双向)第38页/共106页391 1 通过赋值参数通过赋值参数( (“单向传递单向传递”方式方式) ) 传值方向只是:传值方向只是:“上层上层” = =“下层下层”。也。也即,可
36、从主调函数即,可从主调函数A A中通过赋值参数所对应的实参中通过赋值参数所对应的实参将值将值“传入传入”到被调函数到被调函数B B内内( (去使用去使用) ),但不可将,但不可将被调函数被调函数B B内改变后的参数值内改变后的参数值“传出传出”到主调函数到主调函数A A中中( (去接着使用去接着使用) )。系统处理方式为。系统处理方式为: : 被调函数中被调函数中对形参值的改变不影响主调函数处的任一变量的对形参值的改变不影响主调函数处的任一变量的值值( (形参分配有自己的局部于被调函数的存储空间,形参分配有自己的局部于被调函数的存储空间,调用入口处将实参表达式的值赋给该局部变量调用入口处将实参
37、表达式的值赋给该局部变量) )。 第39页/共106页40 通过函数返回值通过函数返回值( (“单向传递单向传递”方式方式) ) 通过函数内使用的通过函数内使用的returnreturn语句语句, , 可将被调函数可将被调函数B B内计算出的最终值内计算出的最终值“传出传出”到主调函数到主调函数A A的的“调用点调用点”处处( (去接着使用去接着使用) )。也即,传值方向。也即,传值方向只是:只是:“下层下层” = =“上层上层”。 第40页/共106页41 全局变量的定义域可延续到整个程序执行结束,因此,全局变量的定义域可延续到整个程序执行结束,因此,只要在函数中没有把该全局变量名说明为其它
38、变量,在只要在函数中没有把该全局变量名说明为其它变量,在所有的函数中都可以直接访问它,也就是说,函数间的所有的函数中都可以直接访问它,也就是说,函数间的数据传递还可以通过全局变量实现,这种传递可以是双数据传递还可以通过全局变量实现,这种传递可以是双向的向的 可从主调函数可从主调函数A A中通过全局变量将值中通过全局变量将值“传入传入”到被调函数到被调函数B B内内( (在在A A中赋值中赋值, , 进入进入B B内后使用该内后使用该值值) ),又可将被调函数,又可将被调函数B B内改变后的全局变量值内改变后的全局变量值“传出传出”到主调函数到主调函数A A中中( (去接着使用去接着使用) )。
39、也即,。也即,传值方向可为:传值方向可为:“上层上层” = =“下层下层”,“下层下层” =“上层上层”。2 通过全局变量(“双向传递”方式)第41页/共106页42 3 3 通过引用参数通过引用参数( (“双向传递双向传递”方方式,式, 有关引用的其它使用方法详见第有关引用的其它使用方法详见第6 6章章) ) 传值方向可为:传值方向可为:“上层上层” = =“下层下层”,“下层下层” = =“上层上层”。即是说,它不仅可向被。即是说,它不仅可向被调函数的形参调函数的形参“传入传入”值值( (调用时的实参值调用时的实参值) ),而且还可通过该形参而且还可通过该形参“传出传出”值。系统处理方值。
40、系统处理方式为式为: : 被调函数中对形参值的使用与改变,就被调函数中对形参值的使用与改变,就是对主调函数中调用语句处所对应实参变量值是对主调函数中调用语句处所对应实参变量值的直接使用与改变的直接使用与改变( (形参不具有自己的局部于被形参不具有自己的局部于被调函数的存储空间,它只是实参变量的一个调函数的存储空间,它只是实参变量的一个“替身替身”) )。第42页/共106页43 4 4 通过数组参数或指针参数通过数组参数或指针参数( (“双向传递双向传递” 方式,指针参数的具体使用方法见第方式,指针参数的具体使用方法见第6 6章章) ) 传值方向可为:传值方向可为:“上层上层” = =“下层下
41、层”,“下层下层” = =“上层上层”。 数组作形参,且数组作形参,且在被调函数内使用或在被调函数内使用或改变改变数组元素数组元素的值的值。系统处理方式为。系统处理方式为: : 对形对形参数组元素的使用与改变,就是对实参数组参数组元素的使用与改变,就是对实参数组元素的直接使用与改变。元素的直接使用与改变。 指针作形参,且指针作形参,且在被调函数内使用或在被调函数内使用或改变改变指针所指变量指针所指变量的值的值。系统处理方式为。系统处理方式为: : 被调函数中对形参指针所指变量值的使用与被调函数中对形参指针所指变量值的使用与改变,就是对实参指针所指变量值的直接使改变,就是对实参指针所指变量值的直
42、接使用与改变。用与改变。第43页/共106页44 数组可作为函数参数,从而把主调函数中的整个数组数组可作为函数参数,从而把主调函数中的整个数组( (实际上是数组的首地实际上是数组的首地址址) )传给了被调函数。传给了被调函数。而后可在被调函数中而后可在被调函数中使用使用或或改变改变传来的那些数组元素的值传来的那些数组元素的值。但注意,若在被调函数内改变数组元素值的话,返回主调函数后,相应实参数组但注意,若在被调函数内改变数组元素值的话,返回主调函数后,相应实参数组元素的值也进行了相同的改变(元素的值也进行了相同的改变(“双向传值双向传值”功能)。功能)。 数组参数数组参数第44页/共106页4
43、5例1. 1. 读如下程序,看执行后会显示出什么结果? ?# #include include void ProcessingFunc(int b, int num); /void ProcessingFunc(int b, int num); /函数原函数原型型/intint型数组形参型数组形参b b,通常省去对元素个数的指定通常省去对元素个数的指定/(/(当然也可以进行指定当然也可以进行指定!)!)void main() void main() int A10=0,1,2,3,4,9,8,7,66,88;int A10=0,1,2,3,4,9,8,7,66,88;cout- before
44、calling, ai= -n;cout- before calling, ai= -n;for(int i=0; i10; i+)for(int i=0; i10; i+)coutAi ; coutAi ; coutendl;coutendl;第45页/共106页46 ProcessingFunc(A, 10); /ProcessingFunc(A, 10); /函数调用函数调用cout- after calling, ai= -n;cout- after calling, ai= -n;for(i=0; i10; i+)for(i=0; i10; i+) coutAi ; coutAi ;
45、 coutendl;coutendl; 第46页/共106页47void ProcessingFunc(int b, int num) void ProcessingFunc(int b, int num) /数组形参数组形参b b,省去了对元素个数的指定省去了对元素个数的指定! !cout- in ProcessingFunc, bi= -n; cout- in ProcessingFunc, bi= -n; for(int i=0; inum; i+)for(int i=0; inum; i+)coutbi ; coutbi ; coutendl;coutendl;int tmp=b0;i
46、nt tmp=b0;b0=bnum-1;b0=bnum-1;bnum-1=tmp; bnum-1=tmp; b1+=100;b1+=100; 第47页/共106页48程序执行后的显示结果如下:- - before calling, ai= -before calling, ai= -0 1 2 3 4 9 8 7 66 880 1 2 3 4 9 8 7 66 88- in ProcessingFunc, bi= - in ProcessingFunc, bi= -0 1 2 3 4 9 8 7 66 880 1 2 3 4 9 8 7 66 88- after calling, ai= -
47、after calling, ai= -88 101 2 3 4 9 8 7 66 088 101 2 3 4 9 8 7 66 0第48页/共106页49例2. 2. 求a a数组中前n n个整数累加和的递归函数sumsum其中使用了数组形参与递归函数。其中使用了数组形参与递归函数。程序执行后的输出结果为程序执行后的输出结果为: :Input 6 integers:Input 6 integers:22 4 -2 9 100 322 4 -2 9 100 3s=136s=136第49页/共106页50#include #include int sum(int a, int n) int su
48、m(int a, int n) if ( n=1 )if ( n=1 ) return a0; return a0;elseelse return ( an-1 + return ( an-1 + sum(a, n-1)sum(a, n-1) ); ); 第50页/共106页51void main()void main()const int n=6;const int n=6;int An; int An; coutInput n integers:endl;coutInput n integers:endl;for(int i=0; in; i+)for(int i=0; iAi;cinAi
49、;int s = sum(A, n);int s = sum(A, n);couts=sendl;couts=sendl; 第51页/共106页52 程序中出现的所有名字(标识符)都必须说明,程序中出现的所有名字(标识符)都必须说明,每个名字(变量名、常量名、参数名、函数名、每个名字(变量名、常量名、参数名、函数名、类名、对象名等)都在程序的一定范围内有意义,类名、对象名等)都在程序的一定范围内有意义,就是该名字的作用域。就是该名字的作用域。 1. 1. 外部存储属性与静态存储属性外部存储属性与静态存储属性2 2名字的生存期与作用域名字的生存期与作用域5.5.4 5.5.4 变量与函数的作用域
50、第52页/共106页53 一个一个C+C+程序由一个主函数和若干用户定义函数程序由一个主函数和若干用户定义函数(或类)组成,当程序的规模较大时,整个程序(或类)组成,当程序的规模较大时,整个程序可能被划分为几个程序文件,关键字可能被划分为几个程序文件,关键字extern(extern(外部外部存储属性存储属性) )和和static(static(静态存储属性静态存储属性) )可以规定所说可以规定所说明的变量名或函数名的作用域在一个程序文件范明的变量名或函数名的作用域在一个程序文件范围内还是扩展到程序文件之外。围内还是扩展到程序文件之外。 外部存储属性与静态存储属性外部存储属性与静态存储属性第5
51、3页/共106页54 C+ C+的存储类别 存储类别主要是针对变量而言的。变量不仅存储类别主要是针对变量而言的。变量不仅具有数据类型(存储空间大小)具有数据类型(存储空间大小), , 而且还具有存而且还具有存储类别(所占存储空间的期限,即生命期)。储类别(所占存储空间的期限,即生命期)。 变 量 的 存 储 类 别 可 分 为 以 下 四 种 : 自 动变 量 的 存 储 类 别 可 分 为 以 下 四 种 : 自 动( (auto)auto)型、寄存器型、寄存器( (register)register)型、外部型、外部( (extern)extern)型、静态型、静态( (static)st
52、atic)型。型。 第54页/共106页55 使用显式存储类别时,变量说明的一般格式变为:使用显式存储类别时,变量说明的一般格式变为: , . , , . , ;n; 其中的其中的“ ”可以是可以是autoauto、registerregister、externextern、staticstatic四个关键字之一。四个关键字之一。 C+ C+程序的数据主要存放在如下两个数据区之程序的数据主要存放在如下两个数据区之中,一个称为中,一个称为静态数据区静态数据区(也称(也称全局数据区全局数据区 - - “一一旦分配,一直拥有旦分配,一直拥有”),另一个称为),另一个称为动态数据区动态数据区(也称(也
53、称堆栈数据区堆栈数据区 - - “入时分配并拥有,出时归还两手入时分配并拥有,出时归还两手空空”)。)。第55页/共106页56 具有具有程序级程序级作用域以及作用域以及文件级文件级作用域的那些变量被分配在静态作用域的那些变量被分配在静态数据区之中。另外,具有数据区之中。另外,具有staticstatic存储类别存储类别的变量也均被分配在静态的变量也均被分配在静态数据区之中。在程序执行时,就为这种变量分配空间并进行数据区之中。在程序执行时,就为这种变量分配空间并进行隐式初隐式初始化始化(将数值量初始化为(将数值量初始化为0 0,将字符量初始化为空格),将字符量初始化为空格),直到程序执直到程序
54、执行结束时才释放行结束时才释放这些存储空间。这些存储空间。 具有其它具有其它局部作用域局部作用域的那些变量被分配在的那些变量被分配在动态数据区动态数据区之中。在程之中。在程序执行时,序执行时,每遇每遇这种变量的作用域开始时这种变量的作用域开始时就为其分配就为其分配一次存储空间一次存储空间(但并不进行隐式初始化),而后(但并不进行隐式初始化),而后, , 在每遇这种变量的在每遇这种变量的作用域结束作用域结束时就时就立即释放立即释放它们所占据的存储空间。它们所占据的存储空间。 第56页/共106页57 变量的存储类别 (1) (1) 自动(自动(autoauto)变量与寄存器(变量与寄存器(reg
55、isterregister)变量变量 这两类变量都是局部变量。均被分配在动态数据区之这两类变量都是局部变量。均被分配在动态数据区之中。它们的中。它们的“生命期生命期”仅在其作用域之内。即是说,这两类仅在其作用域之内。即是说,这两类变量的作用域与变量的作用域与“生命期生命期”具有一致性。具有一致性。 由于由于C+C+编译器默认所有在函数或块内说明的局部变量编译器默认所有在函数或块内说明的局部变量均为自动(均为自动(autoauto)变量变量, , 所以实用程序中根本不需要使用所以实用程序中根本不需要使用关键字关键字autoauto。 说明寄存器(说明寄存器(registerregister)变量
56、时,必须使用存储类别变量时,必须使用存储类别registerregister。如果没有足够多的通用寄存器,则编译器将它如果没有足够多的通用寄存器,则编译器将它们按自动(们按自动(autoauto)变量来处理。变量来处理。 第57页/共106页58 (2) (2) 外部(外部(externextern)变量变量 外部(外部(externextern)变量变量在所有的函数、类和名字空间之在所有的函数、类和名字空间之外说明的变量的作用域从被说明点开始,到所在的程序文外说明的变量的作用域从被说明点开始,到所在的程序文件结束件结束具有具有程序级作用域程序级作用域。它们被分配在静态数据区之中。它们被分配在
57、静态数据区之中。即是说,它们是即是说,它们是作用域最大且作用域最大且“生命期生命期”最长最长的一种变量。的一种变量。在另一个程序文件中如果需要使用同一个变量的话,必须在另一个程序文件中如果需要使用同一个变量的话,必须把这个变量说明为外部(把这个变量说明为外部(externextern)的,表示这个变量的说)的,表示这个变量的说明不在本程序文件中,而在原文件明不在本程序文件中,而在原文件之中。之中。第58页/共106页59 (3) (3) 静态静态( (static)static)变量变量 又可分为又可分为局部静态局部静态变量和变量和全局静态全局静态变量。局部静态变变量。局部静态变量是指在函数或
58、块量是指在函数或块的内部说明的静态变量,它的作用域是的内部说明的静态变量,它的作用域是局部的;对于局部变量:增加局部的;对于局部变量:增加staticstatic说明,使其生存期扩说明,使其生存期扩展到整个程序。而全局静态变量指的是在所有函数的外部展到整个程序。而全局静态变量指的是在所有函数的外部说明的具有单文件级全局性的静态变量。静态全局变量的说明的具有单文件级全局性的静态变量。静态全局变量的生存期为整个程序,作用域为本程序文件,不可扩展。生存期为整个程序,作用域为本程序文件,不可扩展。 两种静态变量都被分配在静态数据区之中,即是说,它两种静态变量都被分配在静态数据区之中,即是说,它们的们的
59、“生命期生命期”都与整个程序的执行期相同都与整个程序的执行期相同。 对于函数:一般(类外)函数的生存期和作用域为整个程对于函数:一般(类外)函数的生存期和作用域为整个程序,静态属性的函数的作用域被限于所在的程序文件,这序,静态属性的函数的作用域被限于所在的程序文件,这时,该函数不能在其它程序文件中使用。时,该函数不能在其它程序文件中使用。 第59页/共106页60 函数的存储类别 函 数 也 分 为 两 种 存 储 类 别 , 一 种 是 外 部函 数 也 分 为 两 种 存 储 类 别 , 一 种 是 外 部(externextern)存储类别,另一种是静态(存储类别,另一种是静态(stat
60、icstatic)存储类别。存储类别。 (1) (1) 外部外部( (extern)extern)函数函数 具有外部(具有外部(externextern)存储类别的函数称为外存储类别的函数称为外部(部(externextern)函数。这种函数具有程序级作用域。函数。这种函数具有程序级作用域。当函数定义时没给出存储类别时,系统默认它为当函数定义时没给出存储类别时,系统默认它为外部(外部(externextern)存储类别,所以实用程序中几乎存储类别,所以实用程序中几乎从不使用从不使用externextern来说明外部函数。来说明外部函数。 第60页/共106页61 例如,如下的两个函数说明是完全
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年人教版高中英语从句练习题30题带答案
- 2024年省燃气经营企业从业人员考试(燃气管网工)练习题及答案四
- 2025年山西省煤矿企业主要负责人安全生产知识和管理能力仿真试题及答案
- 陈强课件Pdf教学课件
- 考点解析-人教版八年级物理上册第4章光现象-光的色散专题训练试卷(详解版)
- 2025年四级车工(数控车)职业技能鉴定理论考试题库(含答案)
- 2025年房地产经营与开发试题及答案
- 2025年湖南省危险货物港口装卸管理人员从业资格考试仿真试题及答案
- 安防监控系统项目施工方案范本
- 九江市注册环保工程师考试(大气污染防治专业案例)全真模拟题库及答案(2025年)
- 医学伦理与医生护士职业道德的边界探讨
- 母婴护理中心(月子会所)项目实施方案
- 作业指导书管理规范规章制度
- 篮球空白战术板
- 医保工作各小组和医保相关制度
- 2023年江苏泰州现代农业发展集团有限公司招聘笔试题库含答案解析
- 第五章 亲核取代反应
- 医院医疗设备购置申请表(采购单)
- 从业人员健康管理制度完整版
- 2022年中交营口液化天然气有限公司招聘笔试题库及答案解析
- 《消防安全技术实务》课本完整版
评论
0/150
提交评论