2023年面向对象程序设计复习辅导三.pdf
面向对象程序设计复习辅导(三)函 数徐孝凯一 个 C+语言程序由若干个程序文献和头文献所组成,每个头文献中通常带有用户类型的定义、符号常量的定义、函数的声明等内容,每个程序文献由若干个函数定义所组成,其中必有一个并且只有一个程序文献中包具有主函数m ain,称此程序文献为主程序文献。函数是C+程序中的基本功能模块和执行单元,这一章专门讨论函数的定义和调用,变量的作用域和生存期等内容。一、函数的定义(一)定义格式类型名 函数名 (参数表 )函数体 类型名)为系统或用户已定义的一种数据类型,它是函数执行过程中通过ret u r n 语句规定返回的值的类型,又称为该函数的类型。当一个函数不需要通过r e tu r n 语句返回一个值时,称为无返回值函数或无类型函数,此时需要使用保存字v o i d 作为类型名。当类型名为in t时,可以省略不写,但为了清楚起见,还是写明为好。函数名是用户为函数所起的名字,它是一个标记符,应符合C+标记符的一般命名规则,用户通过使用这个函数名和实参表可以调用该函数。参数表 又称形式参数表,它包具有任意多个(含 0 个,即没有)参数说明项,当多于一个时其前后两个参数说明项之间必须用逗号分开。每个参数说明项由一种已定义的数据类型和一个变量标记符组成,该变量标记符成为该函数的形式参数,简称形参,形参前面给出的数据类型称为该形参的类型。一个函数定义中的参数表 可以被省略,表白该函数为无参函数,若 参数表用 v o id 取代,则也表白是无参函数,若参数表不为空,同时又不是保存字v o i d,则称为带参函数。函数体 是一条复合语句,它以左花括号开始,到右花括号结束,中间为一条或若干条C+语句。在一个函数的参数表中,每个参数可认为任一种数据类型,涉及普通类型、指针类型、数组类型、引用类型等,一个函数的返回值可以是除数组类型之外的任何类型,涉及普通类型、指针类型和引用类型等。此外,当不需要返回值时,应把函数定义为v o i d类型。(二)定义格式举例(1)v o i d f l ().(2 )v o i d f 2(i n t x).(3)i n t f 3 (i n t x,i n t*p ).(4)c h a r*f 4(c h a r a ).(5 )i n t f 5 (i n t&x,do u b l e d).(6)i n t&f 6(i n t b 1 0 ,i n t n).(7)v o i d f 7 (f 1 o a t c N ,i n t m,f l o a t&m a x).(8)b o o l f 8 (E l e m T y p e *&b t,E 1 e m T y p e&i t e m).在第一条函数定义中,函数名为f l,函数类型为v o i d,参数表为空,此函数是一个无参无类型函数。若 在f l后面的圆括号内写入保存字v o i d,也表达为无参函数。在第二条函数定义中,仅带有一个类型为i n t的形参变量X,该函数没有返回值。在第三条函数定义中,函数名为f 3 ,函数类型为i n t ,函数参数为x和p,其 中x为i nt型普通参数,p为i n t*型指针参数。在第四条函数定义中,函数名为f 4,函数类型为c h a r*,即字符指针类型,参数表中包含一个一维字符数组参数。注意:在定义任何类型的一维数组参数时,不需要给出维的尺寸,当然给出也是允许的,但没有任何意义。在第五条函数定义中,函数名为f 5,返回类型为i n t,该函数带有两个形参,一个为整型引用变量x,另一个为双精度变量d。在第六条函数定义中,函 数 名 为f 6,函数类型为i nt&,即整型引用,该函数带有两个形参,一个是整型数组b,另一个是整型变量n。在这里定义形参数组b所给出的维的尺寸 1 0 可以被省略。在第七条函数定义中,函数名为f 7,无函数类型,参数表中包含三个参数,一个为二维单精度型数组c,第二个为整型变量m,第三个为单精度引用变量m a x。注意:当定义一个二维数组参数时,第二维的尺寸必须给出,并且必须是一个常量表达式,第一维尺寸可给出也可不给出,其作用相同。在第八条函数定义中,函数名为f 8,返回类型为b ool,即逻辑类型,该函数带有两个参数,一个为形参b t,它为E l e m Typ e 的指针引用类型,另一个为形参i t em,它是E l em Ty p e 的引用类型,其 中 E l em Ty p e 为一种用户定义的类型或是通过typ ed ef 语句定义的一个类型的别名。(三)有关函数定义的几点说明1.函数原型语句在一个函数定义中,函数体之前的所有部分称为函数头,它给出了该函数的返回类型、每个参数的顺序和类型等函数原型信息,所以当没有专门给出函数原型说明语句时,系统就从函数头中获取函数原型信息。一个函数必须先定义或声明而后才干被调用,否则编译程序无法判断该调用的对的性。一个函数的声明是通过使用一条函数原型语句实现的,当然使用多条相同的原型语句声明同一个函数虽然多余但也是允许的,编译时不会出现错误。在一个完整的程序中,函数的定义和函数的调用可以在同一个程序文献中,也可以处在不同的程序文献中,但必须保证函数原型语句与函数调用表达式出现在同一个文献中,并且函数原型语句出现在前,函数的调用出现在后。通常把一个程序中用户定义的所有函数的原型语句组织在一起,构成一个头文献,让该程序中所含的每个程序文献的开始(即所有函数定义之前)包含这个头文献(通过#in el u d e命令实现),这样不管每个函数的定义在哪里出现,都可以保证函数先声明后使用(即调用)这一原则的实现。一个函数的原型语句就是其函数头的一个拷贝,当然要在最后加上语句接上结束符分号。函数原型语句与函数头也有细微的差别,在函数原型语句中,其参数表中的每个参数允许只保存参数类型,而省略参数名,并且若使用参数名也允许与函数头中相应的参数名不同。2.常量形参在定义一个函数时,若只允许函数体访问一个形参的值,不允许修改它的值,则应把该形参说明为常量,这只要在形参说明的前面加上const保存字进行修饰即可。如:vo i d f9(c on s t int&x,co n s t char&y);void f 10(c ons t cha r*p,c har k ey);在函数f 9 的函数体中只允许使用x 和 y 的值,不允许修改它们的值。在函数f l 0的函数体中只允许使用p 所指向的字符对象或字符数组对象的值,不允许修改它们的值,但在函数体中既允许使用也允许修改形参key的值。3 .缺省参数在一个函数定义中,可根据需要对参数表末尾的一个或连续若干个参数给出缺省值,当调用这个函数时,若实参表中没有给出相应的实参,则形参将采用这个缺省值。如:vo i d fll(in t x,i nt y=0).int f 12(i nt a,c har o p,int k=10).函数f 11的定义带有两个参数,分别为整型变量x 和 y,并 且 y 带有缺省值0,若调用该函数的表达式为f l l (a,b),将把a 的值赋给x,把 b 的值赋给y,接着执行函数体;若调用该函数的表达式为f ll(a+b),则也是对的的调用格式,它将把a+b 的值赋给X,因 y 没有相应的实参,将采用缺省值0,参数传送后接着执行函数体。函数f 1 2 的定义带有三个参数,其中后两个带有缺省值,所以调用它的函数格式有三种,一种只带一个实参,用于向形参a 传送数据,后两个形参采用缺省值,第二种带有两个实参,用于分别向形参a 和 op传送数据,第三个形参采用缺省值,第三种带有三个实参,分别用于传送给三个形参。若一个函数带有专门的函数原型语句,则形参的缺省值只能在该函数原型语句中给出,不允许在函数头中给出。如对于上述的f l l 和门2 函数,其相应的函数原型语句分别为:v o id f ll(in t x,i nt y=0);i n t fl2(in t a 口 ,ch a r op=+,i n t k10);函数定义应分别改写为:void f 11(i nt x,in t y).int f 1 2(i n t a,c ha r o p,int k).4.数组参数在函数定义中的每个数组参数事实上是指向元素类型的指针参数。对于一维数组参数说明:数据类型数组名 口它与下面的指针参数说明完全等价:数据类型*指针变量名其中(指针变量名就是数组参数说明中的 数组名。如对于f 1 2 函数定义中的数组参数说明i n t a 口,等价于指针参数说明i n t*a。也就是说,数组参数说明中的数组名a 是一个类型为int*的形参。注意:在变量定义语句中定义的数组,其数组名代表的是一个数组,它的值是指向第一个元素的指针常量,这与数组形参的含义有区别。对于二维数组参数说明:数据类型(参数名口 第二维尺寸 它与下面的指针参数说明完全等价:数据类型(*参数名)(第二维尺寸 如 对 于 f 7 函数定义中的二维数组参数说明f 1 oat 等价于指针参数说明float(*c)NO5 .函数类型当调用一个函数时就执行一遍循环体,对于类型为非void的函数,函数体中至少必须带有一条re tu r n 语句,并且每条retu rn 语句必须带有一个表达式,当执行到任一条ret urn 语句时,将计算出它的表达式的值,结束整个函数的调用过程,把这个值作为所求的函数值带回到调用位置,参与相应的运算;对于类型为v o id 的函数,它不需要返回任何函数值,所以在函数体中既可以使用re tu r n 语句,也可以不使用,对于使用的每条re t ur n 语句不允许也不需要带有表达式,当执行到任 一 条 re t u r n 语句时,或执行到函数体最后结束位置时,将结束函数的调用过程,返回到调用位置向下继续执行。6.内联函数当在一个函数的定义或声明前加上关键字i n li n e 则就把该函数声明为内联函数。计算机在执行一般函数的调用时,无论该函数多么简朴或复杂,都要通过参数传递、执行函数体和返回等操作。若把一个函数声明为内联函数后,在程序编译阶段系统就有也许把所有调用该函数的地方都直接替换为该函数的执行代码,由此省去函数调用时的参数传递和返回操作,从而加快整个程序的执行速度。通常可把一些相对简朴的函数声明为内联函数,对于较复杂的函数则不应声明为内联函数。从用户的角度看,调用内联函数和一般函数没有任何区别。下面就是一个内联函数定义的例子,它返回形参值的立方。i n li n e i n t c u b e (i n t n)r e t u r n n*n*n;)二、函数的调用(一)调用格式调用一个已定义或声明的函数需要给出相应的函数调用表达式,其格式为:函数名(口实参表)若调用的是一个无参函数,或所有形参为可选的函数,则实参表 被省略,此时实参表为空。实参表 为一个或若干个用逗号分开的表达式,表达式的个数应至少等于不带缺省值的形参的个数,应不大于所有形参的个数,实参表 中每个表达式称为一个实参,每个实参的类型必须与相应的形参类型相同或兼容(即可以被自动转换为形参的类型,如整型与字符型就是兼容类型)。每个实参是一个表达式,涉及是一个常量、一个变量、一个函数调用表达式,或一个带运算符的一般表达式。如:(1)g l(2 5 )实参是一个整数(2)g2(x )实参是一个变量(3)g 3(a,2*b+3)/第一个为变量,第二个运算表达式(4)g 4(si n(x),,)第一个为函数调用表达式,第二个为字符常量(5)g 5(&d,*p,x /y-1)/分别为取地址运算、间接访问和一般运算表达式任一个函数调用表达式都可以单独作为一条表达式语句使用,但当该函数调用带有返回值时,这个值被自动丢失。对于具有返回值的函数,调用它的函数表达式通常是作为一个数据项使用,用返回值参与相应的运算,如把它赋值给一个变量,把它输出到屏幕上显示出来等。如:(1)f l 0;/作为单独的语句,若有返回值则被丢失(2)y=f 3(x,a);/返回值被赋给y 保存(3 )c o u t f 6 (c,1 0)e n d 1 ;返回值被输出到屏幕上(4)f 2(f 5 (x 1,d l)+1);/f 2 调用作为单独的语句,/f 5调用是f 2实参表达式中的一个数据项(5)f 6 (b,5)=3*w-2;/f 6 函数调用的返回值当作一个左值(6)i f(f 8 (c t,x)c o u t,tr ue,e n d 1;f 6 函数调用作为一个判断条件,若返回值不为0 则执行后面的输出语句,否则不执行任何操作(二)调用过程当调用一个函数时,整个调用过程分为三步进行,第一步是参数传递,第二步是函数体执行,第三步是返回,即返回到函数调用表达式的位置。参数传递称为实虚结合,即实参向形参传递信息,使形参具有确切地含义(即具有相应的存储空间和初值)。这种传递又分为两种不同情况,一种是向非引用参数传递,另一种是向引用参数传递。形参表中的非引用参数涉及普通类型的参数、指针类型的参数和数组类型的参数三种。事实上可以把数组类型的参数归为指针类型的参数。当形参为非引用参数时,实虚结合的过程为:一方面计算出实参表达式的值,接着给相应的形参变量分派一个存储空间,该空间的大小等于该形参类型的长度,然后把已求出的实参表达式的值存入到为形参变量分派的存储空间中,成为形参变量的初值。这种传递是把实参表达式的值传送给相应的形参变量,称这种传递方式为“按值传递”。假定有下面的函数原型:(1)vo i d h l(i n t x,i n t y);(2)b o o 1 h 2(c h a r*p);(3)vo i d h 3(i n t a ,i n t n);(4)c h a r*h 4 (c h a r b N ,i n t m);若采用如下的函数调用:(1)h 1(a,25);假定 a 为 i n t 型(2)b o o l b b=h 2(sp);/假定 sp 为 c h a r *型(3)h 3 (b,10);/假定 b 为 i n t*型(4)c h a r*s=h 4 (c,n+1);/假定 c 为 i n t(*)N 型,n 为 i n t 型当执行第一条语句中的h l (a,2 5)调用时,把第一个实参a的值传送给相应形参x的存储空间,成为x的初值,把常数2 5 传送给形参y 的存储空间,成为y 的初值。当执行第二条语句中的h 2(sp)调用时,将 把 s p 的值,即一个字符对象的存储地址传送给相应的指针形参p的存储空间中,使 P指向的对象就是实参s p 所指向的对象,即*p和*sp 指的是同一个对象,若在函数体中对*p进行了修改,则待调用结束返回后通过访问*sP 就得到了这个修改。当执行第三条语句中的h 3 (b,10)调用时,将把b的值(通常为元素类型为i n t的一维数组的首地址)传送给相应数组变量(实际为指针变量)a的存储空间中,使得形参a 指向实参b所指向的数组空间,因此,在函数体中对数组a的存取元素的操作就是对实参数组b的操作。也就是说,采用数组传送可以在函数体中使用形参数组访问相应的实参数组。当执行第四条语句中的h 4(c,n+1)调用时,将把c的值(通常为与形参b具有相同元素类型和列数的二维数组的首地址)传送给相应二维数组参数(实际为指针变量)a的存储空间中,使得形参b 指向实参c所指向的二维数组空间,在函数体中对数组b的存取元素的操作就是对实参数组C的操作;该函数调用还要把第二个实参表达式n+1 的值传送给形参m中,在函数体中对m 的操作与相应的实参无关。在函数定义的形参表中说明一个数组参数时,通常还需要说明一个整型参数,用它来接受由实参传送来的数组的长度,这样才可以使函数知道待解决元素的个数。当形参为引用参数时,相应的实参通常是一个变量,实虚结合的过程为:把实参变量的地址传送给引用形参,成为引用形参的地址,也就是说使得引用形参是实参变量的一个引用(别名),引用形参所占用的存储空间就是实参变量所占用的存储空间。因此,在函数体中对引用形参的操作事实上就是对被引用的实参变量的操作。这种向引用参数传递信息的方式称为引用传送或按址传送。引用传送的好处是不需要为形参分派新的存储空间,从而节省存储,此外可以使对形参的操作反映到实参上,函数被调用结束返回后,可以从实参中得到函数对它的解决结果。有时,既为了使形参共享实参的存储空间,又不希望通过形参改变实参的值,则应当把该形参说明为常量引用,如:vo i d f 13(c o nst i n t&A,const Nod e*&B,c ha r C);在该函数执行时,只能读取引用形参A和 B的值,不可以修改它们的值。由于它们是相应实参的别名,所以,也可以说,只允许该函数使用A和 B相应实参的值,不允许进行修改,从而杜绝了对实参进行的故意或无意的破坏。进行函数调用除了要把实参传递给形参外,系统还将自动把函数调用表达式执行后的位置(称为返回地址)传递给被调用的函数,使之保存起来,当函数执行结束后,将按照所保存的返回地址返回到本来位置,继续向下执行。函数调用的第二步是执行函数体,事实上就是执行函数头后面的一条复合语句,它将按照从上向下、从左向右的顺序执行函数体中的每条语句,当 碰 到 re tu rn 语句时就结束返回。对于无类型函数,当执行到函数体最后的右花括号时,与执行一条不带表达式的return语句相同,也将结束返回。函数调用的第三步是返回,这事实上是执行一条r e tu rn 语句的过程。当 r e t u r n 语句不带有表达式时,其执行过程为:按函数中所保存的返回地址返回到调用函数表达式的位置接着向下执行。当 r e t u r n 语句带有表达式时,又分为两种情况,一种是函数类型为非引用类型,则计算出r e t u r n 表达式的值,并把它保存起来,以便返回后访问它参与相应的运算;另一种情况是函数的类型为引用类型,则 r e t u r n 中的表达式必须是一个左值,并且不能是本函数中的局部变量(关于局部变量的概念留在下一节讨论),执 行 r e t u r n 语句时就返回这个左值,也可以说函数的返回值是该左值的一个引用。因此,返回为引用的函数调用表达式既可作为右值又可作为左值使用,但非引用类型的函数表达式只能作为右值使用。例如:i n t&f 1 4(i n t a ,i n t n)(i n t k=0;f o r(i n t i=l;i a k )k=i;r e t u r n a k ;)该函数的功能是从一维整型数组a n 中求出具有最大值的元素并引用返回。当调用该函数时,其函数表达式既可以作为右值,从而取出a k 的值,又可以作为左值,从而向a k 赋予新值。如:t t i n c l u d e i n t&f 1 4(i n t a ,i n t n)(i n t k=0;f or (i n t i=l;i a k )k =i;r et u r n a E k ;)v o i d m a i n()o i n t b 8 =2 5,3 7,1 8 ,6 9,5 4,7 3,6 2,3 1 ;。c ou t f l 4(b ,8)en dl;f 1 4(b,5)=8 6;f o r (i n t i=0;i 8;i+)c o u t b i z;。cou t en dl;)该程序的运营结果如下,请读者自行分析。7 32 5 3 7 1 8 8 6 5 4 7 3 6 2 3 1通常把函数定义为引用的情况较少出现,而定义为非引用(即普通类型和指针类型)的情况则常见。(三)函数调用举例程 序1:#i n c 1 u dei n t x k l (i n t n );v o i d m a i n()cou tV 输入一个正整数:;i n t m;c i n m;。i n t s u m=x k l(m)+x k 1 (2*m+l);。cou t s u m e n dl;)i n t x k 1 (i n t n)i n t i ,s=0;。f or(i =l;i =n;i+)s+=i ;r e t u r n s;该程序包含一个主函数和一个x k l 函数,在程序开始给出了一条x k l 函数的原型语句,使得x k l 函数无论在什么地方定义,在此程序文献中的所有函数都可以合法地调用它。注意:主函数不需要使用相应的函数原型语句加以声明,由 于 C+规定不允许任何函数调用它,它只由操作系统调用并返回操作系统。函数x k l 的功能是求出自然数1 至 n之和,这个和就是s的最后值,由 r e t u r n 语句把它返回。在主函数中一方面为m输入一个自然数,接着用m去调用xkl函数返回1 至m之间的所有自然数之和,再用2 *m+l 去调用x k l 函数返回1 至 2 *m+l 之间的所有自然数之和,把这两个和加起来赋给变量s u m,最后输出s u m 的值。假定从键盘上为m 输入的正整数为5 ,则进行x k 1 (m)调用时把m的值5 传送给n,接着执行函数体后返回s的值为1 5,进行x k l (2*m+1 )调用时把2*m+l 的值1 1 传送给n,接着执行函数体后返回s的值为6 6,它们的和8 1 被作为初值赋给s u m,最后输出的s u m 值为8 1。程序2:t t i n cl u d e v oi d x k 2(i n t&a,i n t b);v oi d m a i n ()(i n t x=1 2,y=1 8;。cou t x y =y en d 1;x k 2(x ,y);o c o u t x =x *y=y en dl;)v oi d x k 2 (i n t&a,i n t b)co u t z z a =a b =/z b e n d 1 ;a=a+b;b=a+b ;cou t a=a;e n d 1 ;该程序包含一个主函数和一个x k 2 函数,x k 2 函数使用了两个形参,一个是整型引用变量a,另一个是整型变量b。在主函数中使用x k l (x,y)调用时,将使形参a成为实参x 的别名,在函数体中对a的访问就是对主函数中x的访问,此调用同时把y 的值传送给形参b,在函数体中对形参b的操作是与相应的实参y无关的,由于它们使用各自的存储空间。该程序的运营结果为:x=1 2 y=l 8a=1 2 b =1 8a=3 0 b=4 8x=3 0 y=1 8程序3:#i n c 1 u dev oi d x k 3(i n t*a,i n t *b);v oi d x k 4 (i n t&a,i n t&b);v oi d m a i n()(i n t x =5,y=1 0;co u t ,x=z/x ,,y =,y e n d l;x k 3 (&x ,&y);cou t x =z/x ,”y=n y e n dl;x k 4 (x,y );o c ou t x =,x,Y y=y en dl;v oi d x k 3(i n t*a,i n t*b)(i n t c=*a ;*a =*b;*b=c;)v oi d x k 4(i n t&a,i n t&b)(i n t c=a;a b ;b c;)该程序中的x k 3函数用于互换a和 b 分别指向的两个对象的值,主函数使用x k 3(&x,&y)调用时,分别把x和 y的地址赋给形参a 和 b ,所以实际互换的是主函数中x和 y的值;x k 4 函数用于直接互换a 和 b的值,由于a 和 b 都是引用参数,所以在主函数使用x k 4 (x,y)调用时,执行x k 4函数实际互换的是相应实参变量x和 y的值。此程序的运营结果为:x=5 y=l 0 x=1 0 y =5x =5 y=1 0上述的x k 3和 x k 4 具有完全相同的功能,但由于在x k 3中使用的是指针参数,传送给它的实参也必须是对象的地址,在函数体中访问指针所指向的对象必须进行间接访问运算,所以,定义和调用x k 3不如定义和调用x k 4 直观和简便。程序4:#i n c 1 u decon s t i n t N=8 ;i n t x k 5(i n t a ,i n t n);v oi d m a i n O(i n t b N =1 ,7,2,6,4,5,3,-2 ;o i n t m l=x k 5 (b,8);。i n t m 2 =x k 5(&b 2 ,5);。i n t m 3=x k 5 (b+3,3);c o u t m 1 m 2 ,)m 3 e n d 1;i n t x k 5 (i n t a ,i n t n)(。i n t i,f =1;f o r (i =0 ;i n;i+)f *=a i ;或写成 f*=*a+;o r e t u r n f;)该函数包含一个主函数和一个x k 5 函数,x k 5 函数的功能是求出一维整型数组a En 中所有元素之积并返回。在主函数中第一次调用x k 5 函数时,把数组b的首地址传送给a,把数组b的长度8传送给n,执行函数体对数组a的操作事实上就是对主函数中数组b的操作,由于它们同时指向数组b的存储空间;第二次调用x k 5 函数是把数组b中 b 2 元素的地址传送给a,把整数5 传送给n,执行函数体对数组a n 的操作事实上是对数组b中 b 2 至 b 6 之间元素的操作;第三次调用x k 5 函数是把数组b中 b 3 元素的地址传送给a ,把整数 3 传送给n,执行函数体对数组a n 的操作事实上是对数组b中 b 3 至 b 5 之间元素的操作。该程序的运营结果为:-1 0 0 8 0 7 2 0 1 2 0程序5:#i n c 1 u d e c h a r *x k 6 (c h a r *s p,c h a r*d p);v o i d m a i n()(。c h a r a 1 5 =a b c a d e c a x y b c w;。c h a r b 1 5 ;。c h a r*c l =x k 6(a,b);。c o u t c lz J a,J bendl;c h a r*c 2=x k 6 (a+4,b);c o u t c l a J b e n d 1 ;)c h a r*x k 6 (c h a r*s p,c h a r*d p)(。i f (*s p=0)*d p=,0r;r e t u r n d p;。i n t i =0,j ;f o r (c h a r*p=s p;*p;p+)扫 描 s p所指字符串中的每个字符位置。3 f o r(j=0 ;j =i)d p i+=*p;/若 d p数组的前i 个元素均不等于*p,则把*P写入d p i 元素中d p i =O;写入字符串结束符r e t u r n d p;)x k 6函数的功能是把s p 所指向的字符串,去掉反复字符后拷贝到d p 所指向的字符数组中,并返回d p 指针。在主函数中第一次调用x k 6函数时,分别以a和 b作为实参,第二次调用时分别以a+4 (即 a 4 的 地 址)和 b 作为实参。该程序运营后的输出结果为:a b c d e x y w a b c a d e c a x y b c w a b c d e x y wd e c a x y b w a b c a d e c a x y b c w d e c a x y b w程序6:#i n c l u d e i n t*x k 7 (i n t *&a l,i n t *a 2);i n t*x k 7(i n t*&a l,i n t*a 2)(。c o u t ,z w h e n e n t e r x k 7:*a l,*a 2=,*a 1 M,X*a 2 V e n d l;a l=n e w i n t (2 *a l+4);。a2=new i n t (2*a 2 1);。c o u t ,zw h e n l e a v e x k 7 :*a l,*a 2=X*a l ,z,*a 2 e n d l;r e t u r n a 2;)v o i d m a i n()(i n t x=1 0,y=2 5;i n t *x p =&x,*y p=&y;c o u t ,zb e f o r e c a l l x k 7:*x p,*y p=”V*x p ”,V*y p X e n d l;i n t*i p=x k 7 (x p ,y p );c o u t z,a f t e r c a l l x k 7:*x p,*y p=V*x p V ,*y p X e n d 1;c o u i p=z,*i p e n d l;d e l e t e x p;x p指向的是在执行x k 7 函数时动态分派的对象*a ld e l e t e i p;i p 指向的是在执行x k 7函数时动态分派的对象*a 2在 x k 7 函数的定义中,把形参a l 定义为整型指针的引用,把 a 2 定义为整型指针,当在主函数中运用x k 7(x p,y p)表达式调用该函数时,a l 就成为xp的别名,访问a 1 就等于访问主函数中的x P,而 a 2 同 yp具有各自独立的存储空间,a 2的初值为yp的值,在 x k 7 函数中对a 2 的访问(指直接访问)与 y p 无关。此程序运营结果为:b e f o r e c a l l x k 7:*x p,*y p=1 0,2 5w h e n e n t e r x k 7 :*a 1 ,*a 2=1 0 ,2 5w h e n l e a v e x k 7:*a l,*a 2=2 4 ,4 9a f t e r c a l l x k 7:*x p,*y p=2 4,2 5*i p=4 9三、变量的作用域在一个C+程序中,对于每个变量必须遵循先定义后使用的原则。根据变量定义的位置不同将使它具有不同的作用域。一个变量离开了它的作用域,在定义时为它分派的存储空间就被系统自动回收了,因此该变量也就不存在了。(一)作用域分类变量的作用域具有四种类别:全局作用域、文献作用域、函数作用域和块作用域。具有全局作用域的变量称为全局变量,具有块作用域的变量称为局部变量。1 .全局作用域当一个变量在一个程序文献的所有函数定义之外(并且通常在所有函数定义之前)定义时,则该变量具有全局作用域,即该变量在整个程序涉及的所有文献中都有效,都是可见的,都是可以访问的。当一个全局变量不是在本程序文献中定义时,若要在本程序文献中使用,则必须在本文献开始进行声明,声明格式为:ext e r n(类型名 变量名,变量名,.;它与变量定义语句格式类似,其区别是:不能对变量进行初始化,并且要在整个语句前加上exte r n 保存字。当用户定义一个全局变量时,若没有对其初始化,则编译时会自动把它初始化为0。2.文献作用域当一个变量定义语句出现在一个程序文献中的所有函数定义之外,并且该语句前带有sta t i c 保存字时,则该语句定义的所有变量都具有文献作用域,即在整个程序文献中有效,但在其他文献中是无效的,不可见的。若在定义文献作用域变量时没有初始化,则编译时会自动把它初始化为0。3 .函数作用域在每个函数中使用的语句标号具有函数作用域,即它在本函数中有效,供本函数中的g o to 语句跳转使用。由于语句标号不是变量,应当说函数作用域不属于变量的一种作用域。4 .块作用域当一个变量是在一个函数体内定义时,则称它具有块作用域,其作用域范围是从定义点开始,直到该块结束(即所在复合语句的右花括号)为止。具有块作用域的变量称为局部变量,若局部变量没有被初始化,则系统也不会对它初始化,它的初值是不拟定的。对于在函数体中使用的变量定义语句,若在其前面加上st a tic保存字,则称所定义的变量为静态局部变量,若静态局部变量没有被初始化,则编译时会被自动初始化为0。对于非静态局部变量,每次执行到它的定义语句时,都会为它分派相应的存储空间,并对带初值表达式的变量进行初始化;而对于静态局部变量,只是在整个程序执行过程中第一次执行到它的定义语句时为其分派相应的存储空间,并进行初始化,以后再执行到它时什么都不会做,相称于第一次执行后就删除了该语句。任一函数定义中的每个形参也具有块作用域,这个块是作为函数体的复合语句,当离开函数体后它就不存在了,函数调用时为它分派的存储空间也就被系统自动回收了,当然引用参数相应的存储空间不会被回收。由于每个形参具有块作用域,所以它也是局部变量。在 C+程序中定义的符号常量也同变量同样具有全局、文献和局部这三种作用域。当符号常量定义语句出现在所有函数定义之外,并且在前面带有e x t e r n 保存字时,则所定义的常量具有全局作用域,若在前面带有s t a t i c 关键字或什么都没有,则所定义的常量具有文献作用域。若符号常量定义语句出现在一个函数体内,则定义的符号常量具有局部作用域。一 个 C+程序中的所有函数的函数名都具有全局作用域,所以在程序中所含的任何文献内都可以使用任一函数名构成函数调用表达式,执行相应的函数。具有同一作用域的任何标记符,不管它表达什么对象(如常量、变量、函数、类型等)都不允许重名,若重名系统就无法唯一拟定它的含义了。由于每一个复合语句就是一个块,所以在不同复合语句中定义的对象具有不同的块作用域,也称为具有不同的作用域,其对象名允许重名,由于系统可以区分它们。(二)程序举例程序7 :程序主文献7.c p p#i n c 1 u d e i n t x k 8(i n t n);/函数x k 8 的原型声明i n t x k 9 (i n t n);函数x k 9 的原型声明i n t A A=5;/定义全局变量A Ae x t e r n c o n s t i n t B B=8;定义全局常量 B Bs t a t i c i n t C C=1 2 ;/定义文献域变量C CconstintDD=23;定义文献域常量D I)v o i d m a i n ()i n t x=1 5;x 的作用域为主函数体c o u t u x*x=,x k 8(x)e n d l;c o u t ,zm a i n F i 1 e :A A,B B=,A A,,B B e n d 1;c o u t V m a i n F i 1 e:CC,D D=,C C,,*D D e n d 1 ;c o u t x k 9(1 6)e n d l;)i n t x k 9(i n t n)/n 的作用域为x k 9 函数体(i n t x=1 0;/x的作用域为x k 9函数体c o u t x k 9:x=,x e n d 1;r e t u r n n*x;)程序次文献7-1.c p p#i n c 1 u d e i n t x k 8(i n t n);函数x k 8 的原型声明e x t e r n i n t A A;/全局变量A A 的声明e x t e r n c o n s t i n t B B ;全局常量BB的声明s t a t i c i n t C C=1 2 0;定义文献域变量C Cc o n s t i n t D D=2 3 0;/定义文献域常量DDi n t x k 8(i n t n )/n的作用域为x k 8 函数体(c o u t z za t t a c h F i l e:A A,B B=AA,*B B e n d 1;c o u t z,a t t a c h F i l e:C C,DD=,ZC C V ,V D D V e n d 1;r e t u r n n*n ;此程序包含两个程序文献,定义有各种类型的变量和常量,其中A A为全局变量,B B 为全局常量,C C 为各自的文献域变量,D D 为各自的文献域常量,主函数中的x为作用于主函数的局部变量,x k 9函数中的x为作用于该函数的局部变量,x k 8 和 x