您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > 第2章函数和作用域.
第2章函数和作用域2.1函数定义和调用2.2C++函数特性2.3作用域和存储类型2.4名称空间2.5综合应用实例:Fibonacci数列2.1函数定义和调用C++的任何一个程序都可由一个主函数和若干个子函数组合而成。主函数可以调用子函数,子函数还可以调用其他子函数。C++规定主函数名必须是main,而其他函数可以是库函数或自定义函数。主函数main不仅是程序的入口函数,而且与其他函数相比较还有许多使用上的限制。例如,它不能被其他函数调用,不能用inline和static来说明等。ANSI/ISOC++还规定主函数main的函数类型必须是int,以保证程序的移植性。库函数,又称标准函数,是ANSI/ISOC++编译系统已经预先定义好的函数,程序设计时可根据实际需要,直接使用这类函数,而不必重新定义。调用时,必须在程序中包含相应的头文件,并指明使用名称空间std。自定义函数是用户根据程序的需要,将某一个功能相对独立的程序定义成的一个函数,或将解决某个问题的算法用一个函数来组织。与变量的使用规则相同,在C++程序中一定要先说明和定义函数,然后才能调用函数。C++中每一个函数的定义都是由4个部分组成的,即函数名、函数类型、形式参数表和函数体,其定义的格式如下:2.1.1函数定义函数类型函数名(形式参数表){若干语句}函数体2.1.1函数定义其中,函数名应是一个合法有效的C++标识符;函数头的形式参数又简称为形参。参数表中的每一个形参都是由形参的数据类型和形参名来构成,形数个数可以是0,表示没有形式参数,但圆括号不能省略,也可以是1个或多个形参,但多个形参间要用逗号分隔。由花括号构成的是函数的函数体部分,它可以有若干条语句,用于实现这个函数执行的功能。根据上述定义格式,可以编写一个函数sum,如图2.1所示,注意它们的书写规范。intsum(intx,inty){intz=x+y;returnz;}对齐函数头函数体缩进函数类型函数名形参图2.1定义一个函数sum2.1.1函数定义需要说明的是:(1)C/C++不允许在一个函数体中再定义函数,即禁止嵌套定义,但允许嵌套调用。(2)函数体也可不含有任何语句,这样的函数称为空函数,它仅为程序结构而设定,本身没有任何操作。(3)函数类型决定了函数所需要的返回值类型,它可以是除数组类型之外的任何有效的C++数据类型,包括引用、指针等。一旦指定了函数类型,则须在函数体中通过return语句来指定函数的返回值,且返回值的类型应与函数类型相同,若返回值的类型与函数类型不相同,则程序按类型自动转换方式转换成函数的类型或将return后面的表达式进行强制转换。(4)若函数类型为void时,则表示该函数没有返回值。但仍然可以在函数体中使用return语句“return;”,此时可将“return;”语句理解为是函数体花括号“}”的作用,当流程遇到函数体的“}”时,函数调用结束,控制权返回给主调函数。例如:voidf1(inta){if(a10)return;//return;一旦执行,后面的语句不再被执行…}当a10条件满足时,“return;”语句将控制权返回给主调函数。2.1.2函数的调用和声明1.函数的实参和形参定义一个函数就是为了以后的调用。调用函数时,先写函数名,然后紧跟括号,括号里是实际调用该函数时所给定的参数,称为实际参数,简称实参,并与形参相对应。要注意形参和实参的区别:(1)从模块概念来说,形参是函数的接口,是存在于函数内部的变量。而实参是存在于函数外部的变量。它们不是同一个实体,也就是说,形参变量和实参变量所对应的内存空间不是同一个内存空间。(2)按函数定义时所指定的形参类型,实参除变量外还可以是数值或表达式等,而形参只能是变量。(3)形参在函数调用之前是不存在的,只有在发生函数调用时,函数中的形参才会被分配内存空间,然后执行函数体中的语句,而当调用结束后,形参所占的内存空间又会被释放。2.函数的调用函数调用的一般格式为:函数名(实参表)调用函数时要注意:实参与形参的个数应相等,类型应一致,且按顺序对应,一一传递数据。例如,下面的示例用来输出一个三角形的图案。2.1.2函数的调用和声明[例Ex_Call]函数的调用#includeiostreamusingnamespacestd;voidprintline(charch,intn){for(inti=0;in;i++)coutch;coutendl;}intmain(){introw=5;for(inti=0;irow;i++)printline('*',i+1);//Areturn0;}程序运行的结果如下:2.1.2函数的调用和声明代码中,main函数的for循环语句共调用了5次printline函数(A句),每次调用时因实参i+1值不断改变,从而使函数printline打印出来的星号个数也随之改变。printline函数由于没有返回值,因此它作为一个语句来调用。事实上,对于有返回值的函数也可进行这种方式的调用,只是此时不使用返回值,仅要求函数完成一定的操作。实际上,在C++中,一个函数的调用方式还有很多。例如,对于前面sum函数还可有下列调用方式:intb=2*sum(4,5);//Bintc=1;c=sum(c,sum(c,4));//C其中,B语句把函数作为表达式的一部分,并将返回值参与运算,结果b=18;C是将函数作为函数的实参,等价于“c=sum(1,sum(1,4));”,执行sum(1,4)后,等价于“c=sum(1,5);”,最后结果为c=6。3.函数的声明由于前面函数printline的定义代码是放在main函数中调用语句A之前,因而A语句执行不会有问题。但若将函数printline的定义代码放在调用语句A之后,即函数定义在后,而调用在前,就会产生“printline标识符未定义”的编译错误。此时必须在调用前进行函数声明。2.1.2函数的调用和声明声明一个函数按下列格式进行:函数类型函数名(形参表);可见,函数声明的格式是在函数头的后面加上分号“;”。但要注意,函数声明的内容应和函数的定义应相同。例如,对于前面sum函数和最后一个printline函数可有如下声明:intsum(intx,inty);voidprintline(charch,intn);由于函数的声明仅是对函数的原型进行说明,即函数原型声明,其声明的形参变量名在声明语句中并没有任何语句操作它,因此这里的形参名和函数的定义时的形参名可以不同,且函数声明时的形参名还可以省略,但函数名、函数类型、形参类型及个数应与定义时相同。例如,下面几种形式都是对sum函数原型的合法声明:intsum(inta,intb);//允许原型声明时的形参名与定义时不同intsum(int,int);//省略全部形参名intsum(inta,int);//省略部分形参名intsum(int,intb);//省略部分形参名不过,从程序的可读性考虑,在声明函数原型时,为每一个形参指定有意义的标识符,并且和函数定义时的参数名相同,是一个非常好的习惯。2.1.3值传递在C++中,函数的参数传递有两种方式,一是按值传递,二是地址传递或引用传递。这里先来说明按值传递的参数传递方法,地址传递或引用传递在以后来讨论。当函数的形参定义成一般变量时,如前面printline和sum函数的形参都是一般变量,此时函数的参数传递就是按值传递方式,简称值传递,是指当一个函数被调用时,C++根据实参和形参的对应关系将实际参数的值一一传递给形参,供函数执行时使用。值传递的特点是:(1)若实参指定是变量,则传递的是实参变量的值而不是实参变量的地址。(2)在执行函数代码时,由于对实参数据的操作最终是在形参的内存空间中进行,因此形参值的改变只是改变了形参的内存空间存储的值,而不会改变实参变量所对应的内存空间的值。也就是说,即使形参的值在函数中发生了变化,函数调用结束后,实参的值不会受到影响。例如:2.1.3值传递[例Ex_SwapValue]交换函数两个参数的值。#includeiostreamusingnamespacestd;voidswap(floatx,floaty);//函数原型说明intmain(){floata=20,b=40;couta=a,b=b\n;swap(a,b);//函数调用couta=a,b=b\n;return0;}voidswap(floatx,floaty)//函数定义{floattemp;temp=x;x=y;y=temp;coutx=x,y=y\n;}2.1.3值传递程序的运行结果为:可以看出,虽然函数swap中交换了两个形参x和y的值,但交换的结果并不能改变实参的值,所以调用该函数后,变量a和b的值仍然为原来的值。函数值传递方式的最大好处是保持函数的独立性。在值传递方式下,函数只有通过指定函数类型并在函数体中使用return来返回某一类型的数值。2.1.4函数的默认形参值在C++中,允许在函数的声明或定义时给一个或多个参数指定默认值。这样在调用时,可以不给出实际参数,而按指定的默认值进行工作。例如:voiddelay(intloops=1000)//函数定义,1000为形参loops的默认值{if(0==loops)return;for(inti=0;iloops;i++);//空循环,起延时作用}这样,当有调用delay();//和delay(1000)等效时,程序就会自动将loops当作成1000的默认值来进行处理。当然,也可在函数调用时指定相应的实际的参数值,例如:delay(2000);//形参loops的值为2000在设置函数的默认形参值时要注意:(1)当函数既有原型声明又有定义时,默认参数只能在原型声明中指定,而不能在函数定义中指定。例如:voiddelay(intloops);//函数原型声明//…voiddelay(intloops=1000)//错误:此时不能函数定义中指定默认参数{//…}2.1.4函数的默认形参值(2)当一个函数中需要有多个默认参数时,则形参分布中,默认参数应严格从右到左逐次定义和指定,中间不能跳开。例如:voiddisplay(inta,intb,intc=3);//合法voiddisplay(inta,intb=2,intc=3);//合法voiddisplay(inta=1,intb=2,intc=3);//合法:可以对所有的参数设置默认值voiddisplay(inta,intb=2,intc);//错误:默认参数应从最右边开始voiddisplay(inta=1,intb=2,intc);//错误:默认参数应从最右边开始voiddisplay(inta=1,intb,intc=3);//错误:多个默认参数中间不能有非默认参数(3)当带有默认参数的函数调用时,系统按从左到右的顺序将实参与形参结合,当实参的数目不足时,系统将按同样的顺序用声明或定义中的默认值来补齐所缺少的参数。2.1.4函数的默认形参值[例Ex_Default]在函数定义中设置多个默认参数#includeiostreamusingnamespacestd;voiddisplay(inta,intb=2,intc=3)//在函数定义中设置默认参数{couta=a,b=b,c=c\n;}intmain(){display(1);display(1,5);display(1,7,9);return0;}程序的运行结果如下:2.1.4函数的默认形参值(4)由于对同一个函数的原型可作多次声明,因此在函数声明中指定多个默认参数时,可用多条函数原型声明语句来指定,但同一个参数的默认值只能指定一次。例如,例Ex_Default可改写为:#includeiostreamusingnamespacest
本文标题:第2章函数和作用域.
链接地址:https://www.777doc.com/doc-2154880 .html