《函数和预处理学习教案》由会员分享,可在线阅读,更多相关《函数和预处理学习教案(78页珍藏版)》请在金锄头文库上搜索。
1、会计学1函数函数(hnsh)和预处理和预处理第一页,共78页。4.14.1函数函数(hnsh)(hnsh)概述概述n n所谓函数就是一系列指令或语句的组所谓函数就是一系列指令或语句的组所谓函数就是一系列指令或语句的组所谓函数就是一系列指令或语句的组合体,它有两个目的合体,它有两个目的合体,它有两个目的合体,它有两个目的(md)(md)(md)(md):n n功能分解功能分解功能分解功能分解n n复用复用复用复用第1页/共77页第二页,共78页。4.24.2函数函数(hnsh)(hnsh)定义和调用定义和调用n n在使用(shyng)函数时,要先对函数进行定义,确定它要实现的功能。函数的使用(s
2、hyng)就是调用函数的过程。第2页/共77页第三页,共78页。4.2.14.2.1函数函数(hnsh)(hnsh)定义定义n n任何函数都由函数说明和函数体两部分(bfen)n n形式如下:n n()n nn n函数体;n n函数名函数名是一个有效是一个有效c+标识符,标识符,其后面必须其后面必须跟一对圆括跟一对圆括号(),以号(),以区别于变量区别于变量名及其他用名及其他用户定义户定义(dngy)的的标识名。标识名。函数类型函数类型即函数的返回即函数的返回值的类型,值的类型,如如果不需要函数有果不需要函数有返回值返回值,则只,则只要定义函数的要定义函数的类型为类型为void即即可。可。形式
3、参数表写形式参数表写在括号中在括号中,各参,各参数以逗号隔开,数以逗号隔开,每个参数由参数每个参数由参数类型和参数名表类型和参数名表示。参数个数可示。参数个数可以为,但圆括以为,但圆括号不能省略。号不能省略。函数体函数体由在由在一对花括号中一对花括号中的若干条语句的若干条语句组成,组成,用于实现用于实现这个函数执行的这个函数执行的功能。功能。注:注:C+不允许在一个函数不允许在一个函数体中再定义另一个函数体中再定义另一个函数第3页/共77页第四页,共78页。输入输入(shr)两整数两整数:9 5 9+ 5- 14 9- 5- 4 9* 5- 45void mainvoid main int m
4、1,m2,sum;int m1,m2,sum;coutcout输入输入(shr)(shr)两整数两整数: endl;: m1m2;cinm1m2;coutsetw(10)m1endl;coutsetw(10)m1endl;cout+setw(9)m2endl; for(int cout+setw(9)m2endl; for(int i=0;i10;i+)i=0;i10;i+)cout(-);cout(-);coutendl;coutendl;coutsetw(10)m1+m2endl;coutsetw(10)m1+m2endl;coutsetw(10)m1endl;coutsetw(10)m1
5、endl;cout-setw(9)m2endl; for(int cout-setw(9)m2endl; for(int i=0;i10;i+)i=0;i10;i+)cout(-);cout(-);coutendl;coutendl;coutsetw(10)m1-m2endl;coutsetw(10)m1-m2endl;coutsetw(10)m1endl;coutsetw(10)m1endl;cout*setw(9)m2endl; for(int cout*setw(9)m2endl; for(int i=0;i10;i+)i=0;i10;i+)cout(-);cout(-);coutend
6、l;coutendl;coutsetw(10)m1*m2endl;coutsetw(10)m1*m2endl; 第4页/共77页第五页,共78页。函数调用函数调用主调主调(zh dio)函数函数main()f();f();被调函数被调函数(hnsh)f()void f( )for(int i=0;i10;i+)cout(-);coutendl;函数函数(hnsh)名();名();void mainint m1,m2,sum;cout输入两整数: m1m2;coutsetw(10)m1endl;cout+setw(9)m2endl; f();coutsetw(10)m1+m2endl;couts
7、etw(10)m1endl;cout-setw(9)m2endl; f()coutsetw(10)m1-m2endl;coutsetw(10)m1endl;cout*setw(9)m2endl; f()coutsetw(10)m1*m2endl;第5页/共77页第六页,共78页。函数函数(hnsh)(hnsh)的参数的参数n n函数可以有参数函数可以有参数函数可以有参数函数可以有参数n n函数定义时,定义形式参数表:函数定义时,定义形式参数表:函数定义时,定义形式参数表:函数定义时,定义形式参数表:n n类型类型类型类型1111参数变量名参数变量名参数变量名参数变量名1 1 1 1,类型,类型
8、,类型,类型2222参数变量名参数变量名参数变量名参数变量名2222n n函数调用时传入实际参数函数调用时传入实际参数函数调用时传入实际参数函数调用时传入实际参数:n n 数值数值数值数值(shz)1(shz)1(shz)1(shz)1,数值,数值,数值,数值(shz)2(shz)2(shz)2(shz)2n n实参可以是:常量、变量、表达式实参可以是:常量、变量、表达式实参可以是:常量、变量、表达式实参可以是:常量、变量、表达式n n实参要求:与形参个数相同,顺序对应,类型相容实参要求:与形参个数相同,顺序对应,类型相容实参要求:与形参个数相同,顺序对应,类型相容实参要求:与形参个数相同,顺
9、序对应,类型相容void f(char c, int count)int i;for(i=0;icount;i+)coutc;coutb)max=a;elsemax=b;return max;例:写一个函数例:写一个函数(hnsh),求两个数的最大值,求两个数的最大值void main()int m,n,x;cinmn;x=max(m,n);cout“较大值较大值”xy)return x; return y; 函数返回值语法:return表达式; 将return后面的值作为函数返回值,并将程序控制返回到调用此函数的位置处。 若函数类型(lixng)为void,函数体中就不需要return语句或
10、者return的后面什么也没有。 一旦执行return语句,函数体return后面的语句就不在执行void f (int n)if(n0)return;第8页/共77页第九页,共78页。4.2.24.2.2函数函数(hnsh)(hnsh)的说明的说明n n函数函数函数函数(hnsh)(hnsh)(hnsh)(hnsh)必须先定义后调用必须先定义后调用必须先定义后调用必须先定义后调用n n若函数若函数若函数若函数(hnsh)(hnsh)(hnsh)(hnsh)定义在后而调用在前,需要在调用前进行定义在后而调用在前,需要在调用前进行定义在后而调用在前,需要在调用前进行定义在后而调用在前,需要在调用
11、前进行“函数函数函数函数(hnsh)(hnsh)(hnsh)(hnsh)的说明的说明的说明的说明”。n n说明一个函数说明一个函数说明一个函数说明一个函数(hnsh)(hnsh)(hnsh)(hnsh)的格式如下的格式如下的格式如下的格式如下n n函数函数函数函数(hnsh)(hnsh)(hnsh)(hnsh)类型类型类型类型 函数函数函数函数(hnsh)(hnsh)(hnsh)(hnsh)名(函数名(函数名(函数名(函数(hnsh)(hnsh)(hnsh)(hnsh)参数表);参数表);参数表);参数表);其中,形参的变量名可以其中,形参的变量名可以省略。但要注意,函数说省略。但要注意,函数
12、说明的内容应与函数的定义明的内容应与函数的定义相同。相同。例:例:int max(int x,int y);int max(int,int);函数函数(hnsh)原型原型第9页/共77页第十页,共78页。4.2.3 函数调用函数调用n n调用函数的一般形式调用函数的一般形式(xngsh)(xngsh)如下:如下:n n函数名(实际参数表)函数名(实际参数表)n n实际参数与形参相对应,它是实际调用函数实际参数与形参相对应,它是实际调用函数时所给定的常量,变量或表达式。时所给定的常量,变量或表达式。n n一般地,仅当函数被调用时,系统才会给形一般地,仅当函数被调用时,系统才会给形参分配内存单元,
13、而调用结束后,形参所占参分配内存单元,而调用结束后,形参所占用的内存单元又被释放。用的内存单元又被释放。 第10页/共77页第十一页,共78页。例例: 输输入入两两个个实实数数(shsh),输输出出其其中中较较大大的的数数。其其中中求求两两个个实实数数(shsh)中的较大数用函数完成。中的较大数用函数完成。#includefloat max(float , float );void main()float a, b;cout输入两个实数输入两个实数(shsh):ab;couta和和b中较大数为中较大数为max(a, b) =y?x:y);main( )函函数数调用调用max(2.5,4.7 )
14、函数函数max(2.5,4.7 )return 4.7 主程序后续主程序后续语句语句第11页/共77页第十二页,共78页。注意:实参与形参的个数应该相等,类型应一致,且按顺序一一注意:实参与形参的个数应该相等,类型应一致,且按顺序一一对应传递数据。对应传递数据。在在c+中,调用一个函数的方式可以有很多,例如:中,调用一个函数的方式可以有很多,例如:作为一个语句作为一个语句(yj)不使用返回值不使用返回值max(3,4); 作为表达式的一部分作为表达式的一部分int c=5*max(2,10); 作为函数的实参作为函数的实参int c=0;c=max(max(c,4),10); 第12页/共77
15、页第十三页,共78页。4.34.3函数函数(hnsh)(hnsh)的参数传递的参数传递n n参数类型参数类型(lixng)(lixng)检查检查n nC+C+参数的传递方式:一种为按值传递参数的传递方式:一种为按值传递, ,另一另一种为地址或引用传递。种为地址或引用传递。第13页/共77页第十四页,共78页。1.1.按值传递按值传递(chund)(chund)n n按值传递按值传递n n参数传递的缺省初始化方式是把实参的值拷参数传递的缺省初始化方式是把实参的值拷贝到形参的存储区。贝到形参的存储区。n n函数本身不对实参进行操作,只是函数本身不对实参进行操作,只是(zhsh)(zhsh)处理的实
16、参的本地拷贝。也就是说处理的实参的本地拷贝。也就是说,即使形参的值在函数中发生了变化,实参,即使形参的值在函数中发生了变化,实参的值不会受到影响。的值不会受到影响。第14页/共77页第十五页,共78页。#includefloat max(float ,float );void main()float a,b;cout输入两个输入两个(lin )实数:实数:ab;coutx和和y中较大数为中较大数为max(a,b) = y ? x : y );xyab第15页/共77页第十六页,共78页。# #includeincludevoid swap(int x,int y)void swap(int x
17、,int y) int temp=x; int temp=x; x=y; x=y; y=temp; y=temp; void mainvoid main()() int a=2,b=10; int a=2,b=10; swap (a,b); swap (a,b); cout“a=“a“,b=“b cout“a=“a“,b=“b cout endl; cout endl; 运行运行(ynxng)结果:结果:a=2,b=10该函数的参数是按值传递该函数的参数是按值传递的,不对实参产生影响。的,不对实参产生影响。如果想要实参值改变如果想要实参值改变(gibin),不能用传值方,不能用传值方法。法。形
18、参及形参及变量变量(binling)局局部有效部有效第16页/共77页第十七页,共78页。2. 地址地址(dzh)传递传递n n是指在函数定义时将形参说明成指针。是指在函数定义时将形参说明成指针。n n调用函数时就需要指定地址调用函数时就需要指定地址(dzh)(dzh)值形式值形式的实参。的实参。n n地址地址(dzh)(dzh)传递方式的特点是可以通过改传递方式的特点是可以通过改变形参(指针)所指向的变量来影响实参。变形参(指针)所指向的变量来影响实参。第17页/共77页第十八页,共78页。# # # #includeincludevoid swap(int *x,int *y)void s
19、wap(int *x,int *y) int temp=*x; int temp=*x; * * * *x=*y;x=*y; *y=temp; *y=temp; void main()void main() int a=2int a=2,b=10b=10;swap(&aswap(&a,&b)&b); cout ”a=” a cout ”a=” a “,b=“,b=”b endlb endl; 本程序执行结果如本程序执行结果如下:下:a=10 b=2这说明通过指针这说明通过指针(zhzhn)变量的形变量的形参可以实现函数的参可以实现函数的地址传递地址传递(有关指针(有关指针(zhzhn)内容将在
20、内容将在第五章介绍)。第五章介绍)。第18页/共77页第十九页,共78页。3.3.引用引用引用引用(ynyng)(ynyng)传递传递传递传递n n引用类型引用类型引用类型引用类型n n引用是给已知变量引用是给已知变量引用是给已知变量引用是给已知变量(binling)(binling)(binling)(binling)起一个别名起一个别名起一个别名起一个别名n n当建立引用时,程序用另一个变量当建立引用时,程序用另一个变量当建立引用时,程序用另一个变量当建立引用时,程序用另一个变量(binling)(binling)(binling)(binling)的的的的名字来对其进行初始化。名字来对其
21、进行初始化。名字来对其进行初始化。名字来对其进行初始化。n n引用的声明形式:引用的声明形式:引用的声明形式:引用的声明形式:n n &引用名引用名引用名引用名= = = =变量变量变量变量(binling)(binling)(binling)(binling)名名名名n n对引用的操作实际是对其引用的变量对引用的操作实际是对其引用的变量对引用的操作实际是对其引用的变量对引用的操作实际是对其引用的变量(binling)(binling)(binling)(binling)的操作的操作的操作的操作int a,b=10;int &i=a;i=5; i=b;引用引用(ynyng)在声明时必须初始化在
22、声明时必须初始化引用引用(ynyng)一旦声明一旦声明,就不能再成为其他就不能再成为其他变量的别名变量的别名引用引用(ynyng)与被引用与被引用(ynyng)的变量指的变量指向同一内存地址。向同一内存地址。a,i第19页/共77页第二十页,共78页。例如例如(lr):void swap(int & x, int & y)n n按引用传递按引用传递n n在函数定义时将形参前面加上在函数定义时将形参前面加上引用运算符引用运算符“&”“&”。n n实参传递为同类型的变量。形实参传递为同类型的变量。形参成为参成为(chngwi)(chngwi)实参的引用。实参的引用。n n形参的任何操作都会改变相应
23、形参的任何操作都会改变相应的实参的数据。的实参的数据。第20页/共77页第二十一页,共78页。# # # #includeincludevoid swap(int &x,int &y)void swap(int &x,int &y) int temp=x; int temp=x; x=y;x=y; y=temp; y=temp; void main()void main() int a=2int a=2,b=10b=10;swapswap(a(a,b)b); cout ”a=” a cout ”a=” a “,b=“,b=”b endlb endl; 本程序执行结果如下:本程序执行结果如下:a
24、=10 b=2函数函数swap中的中的int &x和和int &y就是形参的引用就是形参的引用(ynyng)说明。说明。第21页/共77页第二十二页,共78页。 引用经常用来做函数形参和函数的返回引用经常用来做函数形参和函数的返回(fnhu)(fnhu)值。(在运算符重载中也经常用到值。(在运算符重载中也经常用到引用)引用) 使用引用的目的在于使用引用的目的在于 需要改变函数的实参值需要改变函数的实参值 大类型对象做函数参数大类型对象做函数参数 当一个函数返回当一个函数返回(fnhu)(fnhu)一个引用时,它可一个引用时,它可以成为左值。以成为左值。第22页/共77页第二十三页,共78页。4
25、.3.44.3.4函数函数(hnsh)(hnsh)的默认参数值的默认参数值n n在在C+C+中,允许在函数的说明或定中,允许在函数的说明或定义时给一个或多个参数指定默认义时给一个或多个参数指定默认值。调用值。调用(dioyng)(dioyng)时可以不给时可以不给出参数,而按指定的默认值进行出参数,而按指定的默认值进行工作。工作。定义定义定义定义(dngy)(dngy)void fun( int x, int y = 0 )void fun( int x, int y = 0 ) 调用调用调用调用fun(1);fun(1);fun(1fun(1,0); 0); fun(1fun(1,1);1)
26、;第23页/共77页第二十四页,共78页。注意:注意:可以全部或部分参数定义可以全部或部分参数定义(dngy)(dngy)为带默认值,但带默认值的参为带默认值,但带默认值的参数只能放在参数表的最后。数只能放在参数表的最后。 (从右至左逐渐定义(从右至左逐渐定义(dngy)(dngy)) 因为系统进行参数匹配因为系统进行参数匹配(ppi)时是依照从前往后时是依照从前往后(从左往右)的顺序,如果中间参数有默认值,它就(从左往右)的顺序,如果中间参数有默认值,它就无法判断哪些参数使用默认值。无法判断哪些参数使用默认值。f(5);f(3,6);f(2,3,4);例例:以下函数以下函数(hnsh)定义不
27、正确:定义不正确: void f ( int p1=1,int p2,int p3=3 ) void f ( int p1=1,int p2=2,int p3 ) void f ( int p1, int p2=2, int p3)第24页/共77页第二十五页,共78页。2.2.2.2.函数函数(hnsh)(hnsh)又有定义,又又有定义,又有说明时,一般在说明中给有说明时,一般在说明中给出默认形参值。出默认形参值。void f (int x, int y=0);void main() void f (int x, int y)第25页/共77页第二十六页,共78页。3.3.3.3.程序还可以
28、通过重新程序还可以通过重新程序还可以通过重新程序还可以通过重新(chngxn)(chngxn)(chngxn)(chngxn)定义函数原型使本定义函数原型使本定义函数原型使本定义函数原型使本来不带默认值的参数带上默认值,这是使通用函数来不带默认值的参数带上默认值,这是使通用函数来不带默认值的参数带上默认值,这是使通用函数来不带默认值的参数带上默认值,这是使通用函数特定化的有效方法特定化的有效方法特定化的有效方法特定化的有效方法4.4.4.4.但在同一作用域中,函数的某一参数的默认值只但在同一作用域中,函数的某一参数的默认值只但在同一作用域中,函数的某一参数的默认值只但在同一作用域中,函数的某一
29、参数的默认值只能说明一次。能说明一次。能说明一次。能说明一次。void f( int x, int y=0 ); void f( int x=1, int y ); /合法合法 void f (int x, int y=1); /不可不可(bk) void main() void f (int x, int y=1);/可以可以 void f (int x, int y) 第26页/共77页第二十七页,共78页。# # # #include include void f(int x,int y=0);void f(int x,int y=0);void f(int x=1,int y);voi
30、d f(int x=1,int y);void main( )void main( ) f( ); f( ); f(0); f(0); f(1,1); f(1,1); void f(int x,int y)void f(int x,int y)cout “x=” x “,”;cout “x=” x “,”;cout “y=cout “y=” y endl; y endl; 本程序本程序(chngx)的运行结果如的运行结果如下下 x=1,y=0 x=0,y=0 x=1,y=1第27页/共77页第二十八页,共78页。4.4 作用域作用域n n作用域(讨论标识符的有效范围)作用域(讨论标识符的有效范
31、围)作用域(讨论标识符的有效范围)作用域(讨论标识符的有效范围)n n变量变量变量变量(binling)(binling)(binling)(binling)的作用域是指程序中变量的作用域是指程序中变量的作用域是指程序中变量的作用域是指程序中变量(binling)(binling)(binling)(binling)有效的区域。有效的区域。有效的区域。有效的区域。n n变量变量变量变量(binling)(binling)(binling)(binling)的作用域分为三类:文件域、局部的作用域分为三类:文件域、局部的作用域分为三类:文件域、局部的作用域分为三类:文件域、局部域和类域。域和类域。
32、域和类域。域和类域。变量定义位置有效范围文件域程序文件中除函数和程序文件中除函数和类定义以外的部分类定义以外的部分从说明开始到文件结束从说明开始到文件结束局部域块内。(函数,或复块内。(函数,或复合语句内部)合语句内部)从定义到块结束。(函从定义到块结束。(函数或复合语句)数或复合语句)类域类内。(类属性)类内。(类属性)类内类内第28页/共77页第二十九页,共78页。#includeint global; void f(int par)int flocal;if (global) int blocal; blocal=par; blocal=1; flocal=1; global=1; vo
33、id main() int local=2; f(local);全局变量全局变量(binling)全局域定义的变量全局域定义的变量(binling)(定义在所(定义在所有函数之外的变量有函数之外的变量(binling))局部变量局部变量(binling)函数、块中定义的变量函数、块中定义的变量(binling)global/全局变量全局变量localparflocalblocal局部变量局部变量第29页/共77页第三十页,共78页。global作用域flocal作用域作用域blocal作用域作用域local作用域作用域#incledeint global; /全局变量全局变量void f(in
34、t par)int flocal;if (global) int blocal; blocal=par; blocal=1; flocal=1; global=1; void main() int local=2; f(local);第30页/共77页第三十一页,共78页。n n同一作用域,不能声明同名的标志符同一作用域,不能声明同名的标志符n n在没有互相包含关系的作用域中,声明的标在没有互相包含关系的作用域中,声明的标志符互不影响志符互不影响n n具有包含关系的作用域中声明了同名标志符,具有包含关系的作用域中声明了同名标志符,则外层则外层(wicn)(wicn)标志符在内层不可见标志符在内
35、层不可见第31页/共77页第三十二页,共78页。#include int n=1; /n为全局变量为全局变量void Fun() int n=10; / n为函数为函数(hnsh)内局部变量内局部变量 cout “Fun:n=” n 0) int n=5; /n为块内局部变量为块内局部变量 cout “Block:n=”n endl; cout “Main:n= ”n endl; /n为全局变量为全局变量Fun:n=10Block:n=5Main:n=2第32页/共77页第三十三页,共78页。在同一在同一(tngy)(tngy)作用域中,函作用域中,函数的某一参数的默认值只能说数的某一参数的默
36、认值只能说明一次。明一次。void initialize(int printNO, int state=0);void initialize(int printNO, int state=1);/不可不可(bk)void main()void initialize(int printNO, int state=1);/可以可以void initialize(int printNO, int state)第33页/共77页第三十四页,共78页。struct stu;void f()stu s1;void main()stu s2;void f()struct stu;stu s1;void ma
37、in()stu s2;/?第34页/共77页第三十五页,共78页。4.4.14.4.14.4.14.4.1永久变量、临时永久变量、临时永久变量、临时永久变量、临时(lnsh)(lnsh)(lnsh)(lnsh)变量和静态变量和静态变量和静态变量和静态变量变量变量变量变量变量(binling)(binling)的存储空间与生命期的存储空间与生命期变量的存储空间变量的存储空间可以可以(ky)是永久的是永久的(即在程序运行期间该变(即在程序运行期间该变量一直存在)量一直存在)也可以也可以(ky)是暂时的是暂时的(即变量在程序运行到达(即变量在程序运行到达其定义处时才会产生,而其定义处时才会产生,而作
38、用域结束时,变量也随作用域结束时,变量也随之消亡)之消亡)全局变量是永久全局变量是永久的,它们在程序运的,它们在程序运行的过程中一直存在;行的过程中一直存在;而而局部变量大多是临时局部变量大多是临时的,它们只的,它们只在说明它们的作用域内发挥作用,在说明它们的作用域内发挥作用,一旦程序控制离开了这一作用域,一旦程序控制离开了这一作用域,这些局部变量所占空间就会释放。这些局部变量所占空间就会释放。第35页/共77页第三十六页,共78页。静态静态(jngti)(jngti)变量变量(static)(static)n n静态局部变量静态局部变量n n声明方式:在局部变量定义前加上声明方式:在局部变量
39、定义前加上staticstatic标标记。记。n nstaticintlocal;staticintlocal;n n既有在局部域作用的特性,又可以永久存在。既有在局部域作用的特性,又可以永久存在。n n系统系统(xtng)(xtng)给静态的局部变量分配固定的给静态的局部变量分配固定的存储空间,而不是每次执行到该局部域时才存储空间,而不是每次执行到该局部域时才分配空间,所以它能一直保持值。分配空间,所以它能一直保持值。n n静态局部变量只在第一次执行时初始化一次,静态局部变量只在第一次执行时初始化一次,一般的局部变量每次执行到该局部域都需要一般的局部变量每次执行到该局部域都需要初始化。初始化
40、。第36页/共77页第三十七页,共78页。int add()int add() static int sum=0;static int sum=0;sum+;sum+;return sum;return sum; void main()void main() for(int j=0;j10;j+)for(int j=0;j10;j+) coutadd()endl;coutadd()endl; 第37页/共77页第三十八页,共78页。例例49 给出以下程序的执行结果给出以下程序的执行结果(ji gu):#includeint global1=0; /全局变量可以在程序中显式初始化全局变量可以在程
41、序中显式初始化int global2; /全局变量也可以由系统隐式初始化为全局变量也可以由系统隐式初始化为0static int global3=1 ; /静态全局变量静态全局变量void main()int i ; /局部临时变量局部临时变量for(i=0;i3;i+) int temp=l; /局部临时变量,每次循环都会重新初始化局部临时变量,每次循环都会重新初始化 static int perm=l; /静态局部变量,只在第一次初始化静态局部变量,只在第一次初始化 cout “temp=” temp “,perm=”perm endl; +temp; +permtemp=1,perm=1
42、temp=1,perm=2temp=1,perm=3第38页/共77页第三十九页,共78页。n n静态全局变量静态全局变量n n全局变量也可以是静态的。全局变量也可以是静态的。n n静态全局变量的含义完全不同于静态局部变静态全局变量的含义完全不同于静态局部变量:被定义为静态的全局变量只在定义它的量:被定义为静态的全局变量只在定义它的文件中可见,其他文件中不能使用。文件中可见,其他文件中不能使用。n n静态全局变量有两个好处:静态全局变量有两个好处:n n一是信息隐藏一是信息隐藏(yncng)(yncng),n n二是可以在不同的文件中使用意义不同而同二是可以在不同的文件中使用意义不同而同名的变
43、量名。名的变量名。第39页/共77页第四十页,共78页。4.4.2 域运算符域运算符n n局部变量可以隐藏全局变量,那么局部变量可以隐藏全局变量,那么局部变量可以隐藏全局变量,那么局部变量可以隐藏全局变量,那么(nme)(nme)(nme)(nme)在有同名全局和在有同名全局和在有同名全局和在有同名全局和局部变量的情形时如何访问全局变量呢局部变量的情形时如何访问全局变量呢局部变量的情形时如何访问全局变量呢局部变量的情形时如何访问全局变量呢? ? ? ?n n域运算符域运算符域运算符域运算符“:”可以提供对全局变量的访问。以域运算可以提供对全局变量的访问。以域运算可以提供对全局变量的访问。以域运
44、算可以提供对全局变量的访问。以域运算符为前缀的变量表示全局变量。符为前缀的变量表示全局变量。符为前缀的变量表示全局变量。符为前缀的变量表示全局变量。int var=10 ; /全局变量全局变量func() int var; /局部变量局部变量 var=: var; /将全局变量的值赋给局部变量将全局变量的值赋给局部变量第40页/共77页第四十一页,共78页。4.4.3.外部外部(wib)变量变量(extern)n n外部变量说明外部变量说明(shumng)extern(shumng)extern标识:标识:n nexternintvar;externintvar;n n和变量相同,定义在一个文
45、件中和变量相同,定义在一个文件中的函数也可以由另一个文件引用:的函数也可以由另一个文件引用:n nexternvoidfunc(int,int);externvoidfunc(int,int);定义文件定义文件1中的全局变量可以中的全局变量可以(ky)由另一个文件由另一个文件(文件文件2)引用,但需引用,但需要在文件要在文件2中说明一下所要引用的变量,该变量对于文件中说明一下所要引用的变量,该变量对于文件2来说是外部来说是外部变量。变量。注:如果在说明外部变量时不能给变量赋初值注:如果在说明外部变量时不能给变量赋初值第41页/共77页第四十二页,共78页。#include void f() i
46、nt b; b=a*2; /错误错误(cuw) printf(%dn,b);int a=100; main() f(); a+; f();#include void f() int b; extern int a; b=a*2; printf(%dn,b); int a=100; main() f(); a+; f(); 在在f f内内部部增增加加 externexternintinta a; 将将全全局局变变量量a a的的作作用用域域扩扩展展(kuzhn)(kuzhn)到到函函数数f f的的内内部部。第42页/共77页第四十三页,共78页。/* p1.c */#include int a10
47、=0; void main()/* p2.c */#include extern int a10; /也可以也可以(ky)这样写:这样写:extern int a ;void getdata() int k; for(k=0;k10;k+) scanf(%d,&ak); 第43页/共77页第四十四页,共78页。4.4.4.4.4.4.自动自动自动自动(zdng)(zdng)变量变量变量变量(auto)(auto)和寄存器变量(和寄存器变量(和寄存器变量(和寄存器变量(register)register)1 1、自动变量、自动变量、自动变量、自动变量说明加上关键字说明加上关键字说明加上关键字说明
48、加上关键字autoauto: auto int n; auto int n;函数内没说明存储类型的变量都是函数内没说明存储类型的变量都是函数内没说明存储类型的变量都是函数内没说明存储类型的变量都是autoauto的,只是省略的,只是省略的,只是省略的,只是省略(shngl)(shngl)了了了了autoauto。一般用自动存储类型说明的变量都限制在某个程序范围内使用,即为局部变一般用自动存储类型说明的变量都限制在某个程序范围内使用,即为局部变一般用自动存储类型说明的变量都限制在某个程序范围内使用,即为局部变一般用自动存储类型说明的变量都限制在某个程序范围内使用,即为局部变量(包括函数形参)。量
49、(包括函数形参)。量(包括函数形参)。量(包括函数形参)。当程序执行到超出该变量的作用域时,就释放他所占用的内存空间,其值也当程序执行到超出该变量的作用域时,就释放他所占用的内存空间,其值也当程序执行到超出该变量的作用域时,就释放他所占用的内存空间,其值也当程序执行到超出该变量的作用域时,就释放他所占用的内存空间,其值也随之消失了。随之消失了。随之消失了。随之消失了。第44页/共77页第四十五页,共78页。2、寄存器变量、寄存器变量使用使用(shyng)关键字关键字register说说明。明。寄存器类型的变量的目的是将说寄存器类型的变量的目的是将说明的变量放入寄存器内,从而明的变量放入寄存器内
50、,从而加快了程序的运行速度。加快了程序的运行速度。但有时在使用但有时在使用(shyng)这种说这种说明时,若系统寄存器已经被其明时,若系统寄存器已经被其它数据占用,寄存器类型的变它数据占用,寄存器类型的变量就会自动当作量就会自动当作auto变量。变量。 第45页/共77页第四十六页,共78页。堆区堆区 (动态数据动态数据)栈区栈区(函数局部数据)(函数局部数据)全局数据区全局数据区 (全局变量、静态变量全局变量、静态变量)代码区代码区 (程序代码)(程序代码)操操作作系系统统为为一一个个C+C+程程序序的的运运行行(ynxng)(ynxng)所所分分配配的的内内存存分为四个区域,如图程序在内存
51、中的区域所示:分为四个区域,如图程序在内存中的区域所示:C+的内存的内存(ni cn)布局布局代码区:存放程序代码代码区:存放程序代码全局数据区:存放程序的全局数据区:存放程序的全局数据和静态数据,区全局数据和静态数据,区分配分配(fnpi)时全部内存时全部内存清清0栈区:存放程序中的局部栈区:存放程序中的局部变量,区分配变量,区分配(fnpi)时时不处理不处理堆区:存放与指针相关的堆区:存放与指针相关的动态数据,区分配动态数据,区分配(fnpi)时不处理时不处理第46页/共77页第四十七页,共78页。静态生命期静态生命期指的是标识符从程序开始运行时存在,即具有存储指的是标识符从程序开始运行时
52、存在,即具有存储空间,到程序运行结束时消亡,即释放存储空间。空间,到程序运行结束时消亡,即释放存储空间。具有静态生命期的标识符存放在全局数据区,如全具有静态生命期的标识符存放在全局数据区,如全局变量、静态全局变量、静态局部变量。局变量、静态全局变量、静态局部变量。具有静态生命期的标识符在未被用户初始化的情况具有静态生命期的标识符在未被用户初始化的情况下,系统下,系统(xtng)(xtng)会自动将其初始化为会自动将其初始化为0 0。 函数驻留在代码区,也具有静态生命期。所有具函数驻留在代码区,也具有静态生命期。所有具有文件作用域的标识符都具有静态生命期。有文件作用域的标识符都具有静态生命期。变
53、量变量(binling)(binling)的生命期的生命期第47页/共77页第四十八页,共78页。局部生命期局部生命期在函数内部或块中定义的标识符具有局部生命期,其在函数内部或块中定义的标识符具有局部生命期,其生命期开始于执行到该函数或块的标识符声明处,结生命期开始于执行到该函数或块的标识符声明处,结束于该函数或块的结束处。束于该函数或块的结束处。具有局部生命期的标识符存放在栈区。具有局部生命具有局部生命期的标识符存放在栈区。具有局部生命期的标识符如果未被初始化,其内容是随机的。期的标识符如果未被初始化,其内容是随机的。 具有局部生命期的标识符必定具有局部生命期的标识符必定(bdng)(bdn
54、g)具有局部具有局部作用域;但反之不然,静态局部变量具有局部作用域作用域;但反之不然,静态局部变量具有局部作用域,但却具有静态生命期。,但却具有静态生命期。第48页/共77页第四十九页,共78页。动态生命期动态生命期具有动态生命期的标识符由特定的函数调用或运算来创建和具有动态生命期的标识符由特定的函数调用或运算来创建和释放,如调用释放,如调用malloc()malloc()或用或用newnew运算符为变量运算符为变量(binling)(binling)分分配存储空间时,变量配存储空间时,变量(binling)(binling)的生命期开始,而调用的生命期开始,而调用freefree()()或用
55、或用deletedelete运算符释放空间或程序结束时,变量运算符释放空间或程序结束时,变量(binling)(binling)生命期结束。生命期结束。具有动态生命期的变量具有动态生命期的变量(binling)(binling)存放在堆区。存放在堆区。具有动态生命期的标识符如果未被初始化,其内容是随机的。具有动态生命期的标识符如果未被初始化,其内容是随机的。(关于(关于newnew运算和运算和deletedelete运算将在后面章节介绍)运算将在后面章节介绍) 第49页/共77页第五十页,共78页。自动自动变量变量静态变量静态变量 局部局部 全局全局寄存器寄存器变量变量外部变量外部变量(全局变
56、量)(全局变量)程序结束前程序结束前一直保存;一直保存;(生命期)(生命期)多个函数共多个函数共享;(作用享;(作用域)域)初始化;初始化; 否否 否否不定不定有有 有有否否 可以可以 0 0 无无 否否不定不定 有有 可以可以 0变量的存储类型:变量定义变量的存储类型:变量定义(dngy)时可以加上关键字,标识变量的时可以加上关键字,标识变量的存储类型,系统根据其定义存储类型,系统根据其定义(dngy)分配释放存储空间。分配释放存储空间。存储类型关键字存储类型关键字 类型名类型名 变量名表;变量名表;第50页/共77页第五十一页,共78页。4 455内联函数内联函数(hnsh)(hnsh)n
57、 n内联内联(inline)(inline)是内联扩展是内联扩展(kuzhn)(inlineexpansion)(kuzhn)(inlineexpansion)的简称。的简称。n n为什么引入内联函数?为什么引入内联函数?n n在编译时,在编译时,C C十十编译器在遇到调用内联函十十编译器在遇到调用内联函数的地方会用函数体中的代码来替换函数的数的地方会用函数体中的代码来替换函数的调用调用n n好处:节省函数调用带来的参数传递、运行好处:节省函数调用带来的参数传递、运行栈的入栈与出栈等开销,从而提高运行速度。栈的入栈与出栈等开销,从而提高运行速度。n n代价:增加了代码长度。代价:增加了代码长度
58、。第51页/共77页第五十二页,共78页。一般一般(ybn)(ybn)函数调用机制函数调用机制main( ).调调func().保存:返回地址保存:返回地址(dzh)当前现场当前现场恢复:主调函数现场恢复:主调函数现场(xinchng)返回地址返回地址void func( ).第52页/共77页第五十三页,共78页。定义定义: :在一般在一般(ybn)(ybn)函数定义函数定义前加前加inlineinline关键字。关键字。inline int abs(int x) if (x0) return x; else return x;void main( ) int m,m1=2,n,n1=-10
59、; m=abs(m1); n=abs(n1); 编译程序会自动用函数体编译程序会自动用函数体代替代替(dit)函数调用函数调用void main() int m,mt=2,n,n1=-10; / m=abs(m1);转换代码转换代码 if(m10) m=-m1; else m=m1; /n=abs(n1);转换代码转换代码 If (nl=1):”);scanf(“%d”,&n);h=f(n);printf(“%d!=%ld”,n,h);第56页/共77页第五十七页,共78页。例例2 2:梵塔问题:梵塔问题(wnt)(wnt)设设3根柱子根柱子(zh zi)A、B、C,n个盘片个盘片盘片从盘片从
60、A柱搬到柱搬到C柱柱构造递归关系构造递归关系(gun x):f(n,a,b,c):移动:移动n个盘片,从个盘片,从a借助借助b到到cf(n,a,b,c)与与f(n-1, )的递归关的递归关系系(gun x)?f(n-1,a,c,b)move(a,c)f(n-1,b,a,c)void move(char m,char n)printf(“%c%c”,m,n);void f( int n,char a,char b,char c)if(n=1)move(a,c);return;f(n-1,a,c,b);move(a,c);f(n-1,b,a,c);void main()f(3,A,B,C);第57
61、页/共77页第五十八页,共78页。4.74.7函数函数(hnsh)(hnsh)重载重载n n所谓函数重载是指同一个函数名所谓函数重载是指同一个函数名可以对应多个函数的实现。可以对应多个函数的实现。n n作用:作用:n n如何区分?如何区分?n n函数重载要求编译器能够惟一地函数重载要求编译器能够惟一地确定调用一个函数时应执行哪个确定调用一个函数时应执行哪个(nge)(nge)函数代码,确定函数实现函数代码,确定函数实现时,要求从函数参数的个数和类时,要求从函数参数的个数和类型上来区分。型上来区分。n n这就是说,进行这就是说,进行(jnxng)函数重载时,要求函数重载时,要求同名函数在参数个数
62、上不同,或者参数类型上同名函数在参数个数上不同,或者参数类型上不同。否则,将无法实现重载。不同。否则,将无法实现重载。第58页/共77页第五十九页,共78页。#include int add(int x,int y)return x+y;double add (double x,double y)return x+y;complex add(complex c1,complex c2)complex c;c.real=c1.real+c2.real;c.imaginary=c1.imaginary+c2.imaginary;return c;struct complexdouble real;
63、double imaginary;第59页/共77页第六十页,共78页。void main()int m=10, n=11;double x=1.1, y=1.2;cout add(m,n) endl;cout add(x,y) endl;/complex c1,c2,c3;c1.real=1.0;c1.imaginary=2.0;c2.real=3.0;c2.imaginary=4.0;c3=add(c1,c2);cout c3.real “” c2.imaginary “i”; 根据根据(gnj)实参类型实参类型选择函数选择函数第60页/共77页第六十一页,共78页。# #include
64、include int min(int a,int b)int min(int a,int b) return ab ? a: b; return ab ? a: b; int min(int a,int b,int c)int min(int a,int b,int c) int t=min(a,b); int t=min(a,b); return min(t,c); return min(t,c); int min (int a,int b,int c,int d)int min (int a,int b,int c,int d) int t=min(a,b,c); int t=min(a
65、,b,c); return min(t,d); return min(t,d); void main() cout min(13,5,4,9) endl; cout min(-2,8,0)(b) ? (a) : (b) )其中其中(qzhng)(a,b)是宏)是宏MAX的参数表的参数表如果在程序中出现语句如果在程序中出现语句 x=MAX(3,9);则预处理后变成则预处理后变成 x=(39 ? 3:9); /结果为结果为9很显然很显然(xinrn),带参数的宏相当于一个函数的功能,带参数的宏相当于一个函数的功能,但比函数要简洁。但比函数要简洁。第66页/共77页第六十七页,共78页。4.8.24
66、.8.2文件文件(wnjin)(wnjin)包包含命令含命令n n所谓所谓所谓所谓“文件包含文件包含文件包含文件包含”是指将另一个源文件的内容合并到是指将另一个源文件的内容合并到是指将另一个源文件的内容合并到是指将另一个源文件的内容合并到当前源程序中。当前源程序中。当前源程序中。当前源程序中。n nC+C+C+C+语言提供语言提供语言提供语言提供#include#include#include#include命令用来实现:命令用来实现:命令用来实现:命令用来实现:n n#include#include#include#include n n#include”#include”#include”
67、#include”文件名文件名文件名文件名”n n格式格式格式格式(gshi)(gshi)(gshi)(gshi)一:用来包含那些由系统提供的一:用来包含那些由系统提供的一:用来包含那些由系统提供的一:用来包含那些由系统提供的并放在指定子目录中的头文件。并放在指定子目录中的头文件。并放在指定子目录中的头文件。并放在指定子目录中的头文件。n n格式格式格式格式(gshi)(gshi)(gshi)(gshi)二:用来包含那些由用户自己定二:用来包含那些由用户自己定二:用来包含那些由用户自己定二:用来包含那些由用户自己定义的放在当前目录或其他目录下的文件。义的放在当前目录或其他目录下的文件。义的放在
68、当前目录或其他目录下的文件。义的放在当前目录或其他目录下的文件。n nincludeincludeincludeinclude指令可以嵌套使用指令可以嵌套使用指令可以嵌套使用指令可以嵌套使用第67页/共77页第六十八页,共78页。“文件包含文件包含文件包含文件包含”命令可以节省程序设计人员的重复劳动。命令可以节省程序设计人员的重复劳动。命令可以节省程序设计人员的重复劳动。命令可以节省程序设计人员的重复劳动。头文件:头文件:头文件:头文件:externexternexternextern变量声明,函数声明,宏定义变量声明,函数声明,宏定义变量声明,函数声明,宏定义变量声明,函数声明,宏定义.保证
69、所有文件都包含同一个全局变量或函数的同一份声明,如保证所有文件都包含同一个全局变量或函数的同一份声明,如保证所有文件都包含同一个全局变量或函数的同一份声明,如保证所有文件都包含同一个全局变量或函数的同一份声明,如果需要修改声明,则只需改变果需要修改声明,则只需改变果需要修改声明,则只需改变果需要修改声明,则只需改变(gibin)(gibin)(gibin)(gibin)一个头文件一个头文件一个头文件一个头文件头文件提供的声明逻辑上应该属于一个组头文件提供的声明逻辑上应该属于一个组头文件提供的声明逻辑上应该属于一个组头文件提供的声明逻辑上应该属于一个组编译头文件也需要时间,如果文件过大,开销也大
70、,为降低编编译头文件也需要时间,如果文件过大,开销也大,为降低编编译头文件也需要时间,如果文件过大,开销也大,为降低编编译头文件也需要时间,如果文件过大,开销也大,为降低编译时间的开销,有些译时间的开销,有些译时间的开销,有些译时间的开销,有些C C C C实现提供了预编译头文件支持实现提供了预编译头文件支持实现提供了预编译头文件支持实现提供了预编译头文件支持第68页/共77页第六十九页,共78页。4 48 833条件编译条件编译(biny)(biny)命命令令n n条件编译使得条件编译使得同一源程序在同一源程序在不同的编译条不同的编译条件得到不同的件得到不同的目标代码。目标代码。n nC+C
71、+提供提供(tgng)(tgng)的条的条件编译命令形件编译命令形式式一般情况下,源程序中一般情况下,源程序中所有所有(suyu)的语句都的语句都参加编译,但有时也希参加编译,但有时也希望根据一定的条件去编望根据一定的条件去编源文件的不同部分,这源文件的不同部分,这就是就是“条件编译条件编译”。第69页/共77页第七十页,共78页。其中;其中;其中;其中;#ifdef#ifdef#ifdef#ifdef、#else#else#else#else和和和和#endif#endif#endif#endif都是关键字,都是关键字,都是关键字,都是关键字, 111和和和和 222是由若干条预处理命令或语
72、句是由若干条预处理命令或语句是由若干条预处理命令或语句是由若干条预处理命令或语句(yj)(yj)(yj)(yj)组成的。组成的。组成的。组成的。含义含义含义含义: : : :如果标识符己被如果标识符己被如果标识符己被如果标识符己被#define#define#define#define命令定义过,则编译命令定义过,则编译命令定义过,则编译命令定义过,则编译 111,否则编译,否则编译,否则编译,否则编译 222。形式形式形式形式(xngsh)(xngsh)一:一:一:一: #ifdef #ifdef 1 #else #else 2 #endif #endif标识符为宏名标识符为宏名(用宏名做为
73、(用宏名做为编译编译(biny)条件)条件)第70页/共77页第七十一页,共78页。形式形式形式形式(xngsh)(xngsh)(xngsh)(xngsh)一一一一 例:例:例:例:#include#include#include#include#defineN10#defineN10#defineN10#defineN10voidmain()voidmain()voidmain()voidmain() #ifdefN#ifdefN#ifdefN#ifdefN cout“Ncout“Ncout“Ncout“N已定义已定义已定义已定义(dngy):N=”Nendl(dngy):N=”Nendl(
74、dngy):N=”Nendl(dngy):N=”Nendl;#else#else#else#else cout”Ncout”Ncout”Ncout”N未定义未定义未定义未定义(dngy)”endl(dngy)”endl(dngy)”endl(dngy)”endl;#endif#endif#endif#endif 第71页/共77页第七十二页,共78页。形式形式(xngsh)(xngsh)二:二:#ifndef#ifndef 1#else#else2#endif#endif这与前一种形式的区别仅在于这与前一种形式的区别仅在于:如果标识符没有被如果标识符没有被#define命令命令(mng lng
75、)定义过,则就编译定义过,则就编译,否则编译,否则编译。标识符为宏名标识符为宏名(用宏名做为(用宏名做为编译编译(biny)条件)条件)第72页/共77页第七十三页,共78页。形式形式(xngsh)(xngsh)三:三:#if#if1 1#elif#elif2 2#else#else n#endif#endif其中其中,#if,#elif,#else和和#endif是关键字是关键字.含义是:如果含义是:如果为为true就编译就编译(biny),否则如果否则如果为为true就编译就编译(biny),如果各表达式都不如果各表达式都不true就编译就编译(biny)。用表达式做为用表达式做为编译编译
76、(biny)条件条件第73页/共77页第七十四页,共78页。形式形式形式形式(xngsh)(xngsh)(xngsh)(xngsh)三三三三 例:例:例:例:# #includeinclude#define N 10#define N 10void main()void main() #if N0 #if N0 cout 0” endl; cout 0” endl; #elif N0 #elif N0 cout “N0” endl; cout “N0” endl; #else #else cout “N=0” endl; cout “N=0” endl; #endif #endif 第74页/
77、共77页第七十五页,共78页。4.8.4 断言断言(dunyn)n nassert宏n nassert.h头文件定义n n测试表达式的值:如果表达式值为0,打印错误信息,并调用(dioyng)abort()以结束程序assert(x10);第75页/共77页第七十六页,共78页。#include #include void main()int x;coutx;assert(x10);cout“x=“xendl;若输入(shr)30Assertion fail: x10,file *.cpp,line 7#include #include #define NDEBUGvoid main()int x;coutx;assert(x10);cout“x=“xendl;第76页/共77页第七十七页,共78页。内容(nirng)总结会计学。实参可以(ky)是:常量、变量、表达式。swap(&a,&b)。当一个函数返回一个引用时,它可以(ky)成为左值。具有包含关系的作用域中声明了同名标志符,则外层标志符在内层不可见。printf(%dn,b)。scanf(%d,&ak)。所有具有文件作用域的标识符都具有静态生命期。(关于new运算和delete运算将在后面章节介绍)。inline对编译器来说只是一个建议,编译器可以(ky)选择忽略该建议第七十八页,共78页。