1、第四章第四章 函数和作用域函数和作用域第四章第四章 第一节第一节 函数的定义和说明函数的定义和说明第四章第四章 一、一、函数的定义格式函数的定义格式 在C+中一个函数的定义格式函数的定义格式 :()函数的定义格式的几点说明:1、构成了函数的函数 头。2、用花括号括起来的组成了函数体。函 数体内无论多少条语句,花括号是不可省的。第四章第四章 3、是该函数的类型,即为该函数返回值的类 型,如果该函数没有返回值,只是一个过程调用,则 该函数的类型为 void,在C+程序中函数的类型不 可省略。4、是由0个、1个或多个参数组成,参数个 数为0,表示没有参数,但是圆括号不可省,多个参 数之间应用逗号分隔
2、;每个参数包括参数类型和参 数名。中的参数称为形式参数,简称形中的参数称为形式参数,简称形 参。参。形参在该函数被调用时才被初始化的。形参的 使用将使被调用函数可以从调用函数那里获取数 据。如果被调用函数不需要从调用函数那里获取数 据,则该函数参数为空。第四章第四章 二、二、函数的说明方法函数的说明方法:1 1、说明调用函数的方法说明调用函数的方法:();函数函数说明说明又又称为原型说明称为原型说明。其格式同于定义函数时的函数头,包括函数的类型、函数名和函数参数的个数及其对应的类型。原型说明与C语言中的简单说明是不同的。2 2、在在C+C+中函数的说明原则中函数的说明原则:如果一个函数定义在先
3、,调用在后,调用前可以不必说明;如果一个函数定义在后,调用在先,调用前则必须说明。例1、使用原型说明的例子第四章第四章#include void fun1(),fun2(),fun3();void main()cout”It is in main.endl;fun2();coutIt is back in main.endl;void fun1()coutIts in fun1.”endl;fun3();cout”Its back in fun1.”endl;第四章第四章 void fun2()coutIts in fun2.endl;funl();cout”Its back in fun2.
4、end1;void fun3()coutIts in fun3.endl;第四章第四章 第二节第二节 函数的调用函数的调用第四章第四章 一、函一、函数的值和类型数的值和类型:一个函数被定义以后就是为了将来对它调用,函数的调用是用一个表达式来表示的。函数函数调用格式调用格式:()、可以是0个、1个或多个实在参数,如 果是多个参数用逗号分隔。、每个参数是一个表达式。、实参的个数由形参决定,实参是用来在调用函 数时给形参初始化的,因此实参的个数和类型要 与形参的个数和类型一致,并且初始化时是按其 位置对应进行。第四章第四章 二、二、函数的调用函数的调用:1、函数的传值调用函数的传值调用:该调用同C语
5、言,分如下两种:(1 1)、传值调用:)、传值调用:传递变量本身值的传递变量本身值的函数函数调用调用。使用传值调用时,调用函数的实参用常量、变量 值或表达式,被调用函数的形参用变量名,实参将复 制副本形参。传值调用的特点是在被调用函数中形参的改变将传值调用的特点是在被调用函数中形参的改变将不影响调用函数的实参。不影响调用函数的实参。例2、一个传值调用的例子。第四章第四章#include void swap1(int x,int y)int temp;temp=x;x=y;/将y值赋予了x y=temp;/将x的值赋予y coutx=x,y=yendl;void main()int a(5),b
6、(9);swap1(a,b);couta=a,b=bendl;第四章第四章 (2 2)、传址调用:)、传址调用:传递变量传递变量地址地址值的值的函数函数调用调用。使用传址调用方式时,调用函数的实参用地址值,被调用函数的形参用指针,调用时将实参地址值传送给形参指针,即让指针指向实参变量或对象。在被调在被调用函数中可以通过改变形参指针所指向的实参变量值用函数中可以通过改变形参指针所指向的实参变量值来间接改变实参值。来间接改变实参值。传址调用的特点是可以通过改变形参所指向的变传址调用的特点是可以通过改变形参所指向的变量值来影响实参。量值来影响实参。例3、一个传址调用的例子。第四章第四章#includ
7、e void swap2(int*x,int*y)int temp;temp=*x;*x=*y;*y=temp;coutx=*x,y=*yendl;void main()int a(5),b(9);swap2(&a,&b);couta=a,b=bendl;第四章第四章 2 2、引用调用、引用调用:引用调用是C+中的一种函数调用方式,C语言中没有这种调用方式。引用调用时,调用函数的实参用变量名或对象名,被调用函数的形参用变量或对象的引用。而实际实际传送的是地址值传送的是地址值。在被调用函数中改变形参值,则调在被调用函数中改变形参值,则调用函数中实参值也被改变。用函数中实参值也被改变。引用调用具有
8、传址调用的特点,而在操作中又比引用调用具有传址调用的特点,而在操作中又比传址调用方便、直观。传址调用方便、直观。因此,在C+程序中多用引用调用。例4、一个引用调用的例子第四章第四章#include void swap3(int&x,int&y)int temp;temp=x;x=y;y=temp;coutx=x,y=yendl;void main()int a(5),b(9);swap3(a,b);couta=a,b=bendl;第四章第四章 三、三、函数的嵌套调用函数的嵌套调用:C+程序中允许函数的嵌套调用嵌套调用:函数调用函数调用是是逐级逐级调用,然后逐级返回的过程。调用,然后逐级返回的过
9、程。即在调用A函数的过程中,可以调用B函数,在调用B函数的过程中,还可以调用C函数。当C函数调用结束后,返回到B函数,当B函数调用结束后,再返回到A函数。四、函数的递归调用:四、函数的递归调用:递归调用:递归调用:是指在调用一个函数时,直接或间接是指在调用一个函数时,直接或间接地调用该函数自身的过程。地调用该函数自身的过程。直接递归调用:直接递归调用:是指在调用一个函数的过程中,是指在调用一个函数的过程中,又调用了该函数。又调用了该函数。第四章第四章 间接递归调用:间接递归调用:是指在调用一个函数的过程中调是指在调用一个函数的过程中调用了另一个函数,而在另一个函数中又调用了该函数。用了另一个函
10、数,而在另一个函数中又调用了该函数。1 1、递归调用的特点及方法:递归调用的特点及方法:(1 1)、特点:)、特点:使用递归调用方法编写的程序简洁清 晰,可读性强,但是程序在执行时占用的时间和空 间都比较大。(2 2)、方法)、方法:将原有问题能够分解为一个新问题,而 新问题又用到原有问题的解法,这就出现了递归。实际中,有限的递归调用是有意义的,而无限的递 归调用是没有意义的。数学中求正整数阶乘的问题 就是典型的有限的递归调用的例子。第四章第四章 2 2、递归调用的过程:、递归调用的过程:具体可分为两个阶段:第一个阶段称为“递推递推”阶段。这一阶段将原有问题不断地分解为新的子问题,逐渐从未知的
11、向已知的方向推测,最终到达已知的条件,即递归结束条件,这时递推阶段结束。第二个阶段称为“回归回归”阶段。此阶段是从已知的阶段出发,按照“递推”的逆过程,逐一求值回归,最后到达递推的开始处,结束回归阶段,完成递归调用。如求正整数阶乘的问题。第四章第四章 第第三三节节 函数函数参数及内联函数参数及内联函数第四章第四章 一一、函数参数的求值顺序:、函数参数的求值顺序:当一个函数带有多个多个参数时,C+语言没有规定在函数调用时实参的求值顺序,而编译器根据对代码进行优化的需要自行规定对实参的求值顺序。因此应注注意意不同编译系统中,函数参数求值的顺序可能不同,当实参表达式中出现有副作用的运算符时,可能产生
12、二义性。二二、设置函数参数的默认值:、设置函数参数的默认值:在C+语言中,允许在函数的说明或定义时说明或定义时给一个或多个参数指定默认值。具体规则规则如下:第四章第四章 (1)、设置参数默认值时,要求从右向左设置,即要求 在一个指定了默认值的参数的右边不能出现没有指 定默认值的参数。(2)、调用设置了默认参数的函数时,对应实参如果 没有,则用默认值,如果存在,则用实参值。(3)、如果一个函数有说明出现时,设置参数默认值 应放在函数说明中。例5、一个将参数默认值设置在函数的说明中的例子 第四章第四章#includeint m(8);int add_ int(int x,int y=7,int z
13、=m);void main()int a(5),b(15),c;int s=add_int(a,b,c);coutsendl;int add _ int(int x,int y,int z)return x+y+z;运行结果:28第四章第四章 三、三、数组名可作为函数参数数组名可作为函数参数:数组作函数参数可以分为三种情况,这三种情况所采用的调用机制不同,但是结果相同。1 1、形参和实参都用数组形参和实参都用数组:调用函数的实参用数组名,被调用函数的形参用数组,这种调用的机制是形参和实参共用内存中的同一个数组。因此,在被调用函数中改变了数组中某个元素的值,对调用函数该数组的该元素值也被改变。例
14、6:#include int a8=1,3,5,7,9,11,13;void fun(int b,int n)for(int i=0;in-1;i+)第四章第四章 b7+=b i;void main()int m=8;fun(a,m);couta7endl;运行后结果为:492 2、形参和实参都用对应数组的指针形参和实参都用对应数组的指针:在C+中,数组名被规定为是一个指针,该指针便是指向该数组的首元素的指针。实际中,形参和实参一个用指针,另一个用数组也是可以的。在使用指针时可以用数组名,也可以用另外定义的指向数组的指针。第四章第四章 例7:#include int a8=1,3,5,7,9,
15、11,13;void fun(int*pa,int n)for(int i=0;in-1;i+)*(pa+7)+=*(pa+i);void main()int m=8;fun(a,m);/a是数组的数组名是数组的数组名,是一个地址值是一个地址值 couta7endl;运行结果:49第四章第四章 3 3、实参用数组名实参用数组名,形参用引用形参用引用。采用这种情况时,应先用类型定义语句定义一个与实参数组类型相一致的数组类型。四、内联函数:四、内联函数:1 1、内联函数引内联函数引入入的原因的原因:引入内联函数的目的是为了提高提高程序中函数调用程序中函数调用的效率问题的效率问题。引入内联函数,在程
16、序编译时,编译器将程序中出现的内联函数的调用表达式用内联函数的函数体来进行替换,因此,引入内联函数引入内联函数是以目标是以目标代码的增加为代价来换取时间的节省。代码的增加为代价来换取时间的节省。第四章第四章 2 2、内联函数的定义方法内联函数的定义方法:在函数头前加上关键字inline,其格式:inline inline()3 3、使用内联函数应注意的事项使用内联函数应注意的事项:(1)、内联函数通常情况下是将一些函数体不大,而 且使用频繁的函数;(2)、内联函数体内不允许用循环语句和开关语句不允许用循环语句和开关语句;(3)、内联函数的定义必须出现在第一次调用第一次调用之前;(4)、类体内定
17、义的所有成员函数都是内联函数。第四章第四章 例例8 8、编程求编程求1 11010中各个数的平方。中各个数的平方。#include inline int power_int(int x)return(x)*(x);void main()for(int i=1;i=10;i+)int p=power_int(i);couti*i=pendl;运行结果:分别是110 的平方。第四章第四章 第第四四节节 函数的函数的重载重载第四章第四章 一一、函数重载定义:、函数重载定义:函数重载:函数重载:是指同一个函数名对应着多个不同的是指同一个函数名对应着多个不同的实现。实现。二、二、定义重载函数时的注意事项
18、:定义重载函数时的注意事项:1、多个重载的同名函数在定义时要注意它们的参 数 的不同,主要是参数的个数、类型和顺序个数、类型和顺序的不同。2、在选择重载函数的不同实现时,主要根据参数不同 进行选择。例例9、求两个操作数之和。求两个操作数之和。#include int add(int,int);double add(double,double);第四章第四章 void main()coutadd(5,10)endl;coutadd(5.0,10.5)endl;int add(int x,int y)return x+y;double add(double a,double b)return a+
19、b;程序的输出结果程序的输出结果:15 15.5第四章第四章 例例1010、找出几个找出几个intint型数中最小者。型数中最小者。#include int min(int a,int b);int min(int a,int b,int c);int min(int a,int b,int c,int d);void main()coutmin(13,5,4,9)endl;coutmin(-2,8,0);int min(int a,int b)return ab?a:b;int min(int a,int b,int c)第四章第四章 int t=min(a,b);return min(t,
20、c);int min(int a,int b,int c,int d)int t1=min(a,b);int t2=min(c,d);return min(t1,t2);运行结果:运行结果:4 -2 第四章第四章 第第五五节节 作用域作用域第四章第四章 一、一、用作标识符的作用域规则用作标识符的作用域规则:作用域又称作用范围作用域又称作用范围。在程序中出现的各种标识符,它们的作用域是不同的。标识符只能在说明它或定标识符只能在说明它或定义它的范围内是义它的范围内是“可见的可见的”,即是可以进行存取或访问操作的;而在该范围之外是而在该范围之外是“不可见不可见”的的,也就是指不可以进行存取或访问操作
21、的。二、二、作用域的种类作用域的种类:作用域的按大小可分为:1、程、程序级序级:作用域最大,属于程序级作用域的有外部 函数和外部变量。2、文件级文件级:仅在所定义的文件内,属于文件级作用域 的有内部函数和外部静态类变量。第四章第四章 3 3、函数级函数级:在它所定义的函数体内,属于函数级作用 域的有函数的形参和在函数内定义的自动类变量和 内部静态类变量以及语句标号。4 4、块级块级:在某一程序块内,属于块级作用域的有定 义在分程序、if语句、switch 语句以及循环语句中 的自动类变量和内部静态类变量。三、三、关于重新定义标识符的作用域规定关于重新定义标识符的作用域规定:在某个作用范围内定义
22、的标识符在该范围内的子在某个作用范围内定义的标识符在该范围内的子范围内中可以重新定义范围内中可以重新定义,这时原定义的标识符在子范围内是不可见的,但是它还是存在的,只是在子范围内由于出现了同名的标识符而被暂时地隐藏起来。出了子范围后,它又是可见的。第四章第四章 第七节第七节 存储类及系统函数存储类及系统函数第四章第四章 一、存储类:一、存储类:1 1、变量的存储类:、变量的存储类:(1)(1)、变量存储类的种类:、变量存储类的种类:、自动类、自动类:是在函数体或分程序内定义的变量是在函数体或分程序内定义的变量,定义时可加autoauto说明符,也可以省略。、寄存器类:、寄存器类:也也是定义在函
23、数体内或分程序内是定义在函数体内或分程序内的变的变量量,定义时前边加说明符rigesterrigester。寄存器类变量有 可能被存放到CPU的通用寄存器中,此时可提高存取 速度,但是由于CPU的通用寄存器数量有限,如果没 被存放到通用寄存器中便按自动类变量处理。、外部类:、外部类:是一种定义在函数体外是一种定义在函数体外,定义时不加任定义时不加任 何存储类说明的一种变量何存储类说明的一种变量。外部变量在引用之前需外部变量在引用之前需第四章第四章 要说明要说明,说明外部变量时应在其前面加说明符 extern。外部变量的定义和说明是两回事定义和说明是两回事:在一个程 序中,一个外部变量只能定义只
24、能定义一次,但是可以说明可以说明 多次多次。外部变量不管是在同一文件中,还是在另 外一个文件中被引用,都要在引用前必须对它进行 说明。、静态类(内部静态和外部静态):内部静态类变量内部静态类变量也也是在函数体内或分程序内定是在函数体内或分程序内定 义义的变量,的变量,用说明符static说明。它的作用域与自 动变量相同,但是它的生存期(即寿命)是长的,是一是一 种可见性与存在性不一致的变量种可见性与存在性不一致的变量:在定义它的作用第四章第四章 域外,它虽然不可见,但是它仍然存在,且没有被释放 掉,一旦它回到作用域后,仍然保留其原来的值。外部外部静态类变量静态类变量被定义在函数体外,被定义在函
25、数体外,也用说明符 static说明,其作用域是文件级的,可见性与存在可见性与存在 性性也是也是不一致的不一致的(它的作用域不是整个程序,但其 生存期却在整个程序)。(2)(2)、不同存储类变量的作用域和寿命:、不同存储类变量的作用域和寿命:、作用域分为程序级、文件级、函数级和分程序级、寿命分为长和短两种。存放在内存的静态区的寿 命长,存放在寄存器和内存的动态区的寿命短。2 2、函数的存储类函数的存储类:(1)(1)、函数存储类的种类函数存储类的种类:函数存储类分两种:内部函数和外部函数。第四章第四章 a a、内部函数内部函数:用关键字static 说明的函数,也称为 静态函数。在定义它的文件
26、中可以被调用,而在同一 程序的其他文件中不可被调用。定义格式定义格式:static static()b b、外部函数外部函数:用关键字extern 说明的函数,其作用 域在整个程序中,包含组成该程序的若干个文件。定义格式定义格式:第四章第四章 extern extern()一般情况下,关键字extern可以省略。二、二、系统函数系统函数:1 1、使用系统函数的注意事项、使用系统函数的注意事项:C+系统将所提供的系统函数的说明分类放在不同的.h.h 文件中。因此,编程者在使用系统函数时,应该注意:(1)、了解你所使用的C+系统提供了哪些系统函 数。第四章第四章 (2)、知道某个系统函数的说明在哪
27、个头文件中。(3)、调用一个函数时,一定要将该函数的功能、参 数和返回值搞清楚。否则难以正确地使用该函数。2 2、字符串处理函数字符串处理函数:(1)、字符串长度函数字符串长度函数 strlenstrlen()():功能是返回一个 字符串的长度。其原型说明为:intint strlen(costrlen(con nstst char char*s s););(2)、字符串拷贝函数字符串拷贝函数strcpystrcpy()():功能是用一个字 符串去更新另一个字符串,从而实现字符串的复 制。该函数原型说明:char char*strcopystrcopy(char(char *s1,s1,con
28、const char st char*s2);s2);char char*strstrn ncpy(charcpy(char *s1,s1,conconst char st char*s2,int n);s2,int n);第四章第四章 (3)、字符串连接函数字符串连接函数 strcatstrcat()():功能是将一个字符 串添加到另一个字符串的后面,形成一个包含了两 个字符串的新字符串。该函数的原型说明:char char*strstrc catat(char (char*s1,char s1,char*s2);s2);char char*strstrncncat(charat(char
29、s1,char s1,char s2,int n);s2,int n);(4)、字符串比较函数字符串比较函数 strcmp():功能是用来比较两 个字符串是否相等。如果该函数返回值为0,说明比 较的两字符串相等;如果返回值为大于O的值,说明比 较的两个字符串不相等,第一个大于第二个,如果返 回值为小于O 的值,说明第一个小于第二个。该函数的原型说明:第四章第四章 .intint strstrc cmp(constmp(const char char*s1,const char s1,const char*s2s2).int int strncmp(costrncmp(con nstst chch arar *s1s1,const char,const char*s2,int n);s2,int n);第四章第四章 :第四章第四章 :第四章第四章 :第四章第四章 :