




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、 在构造化程序设计中,函数是将义务进展模块划分的根在构造化程序设计中,函数是将义务进展模块划分的根本单位。一个函数实现一项功能。本单位。一个函数实现一项功能。 在面向对象程序设计中,函数是对数据的一项操作,也在面向对象程序设计中,函数是对数据的一项操作,也是实现一项功能。是实现一项功能。 要掌握函数的运用,必需了解函数调用时的内部实现机要掌握函数的运用,必需了解函数调用时的内部实现机制,以及与此相关的内存分配机制、变量生命期和作用域。制,以及与此相关的内存分配机制、变量生命期和作用域。 本章还将引见关于函数重载的概念,引见递归算法本章还将引见关于函数重载的概念,引见递归算法、内联函数、默许参数
2、函数以及多文件组织、编译预处、内联函数、默许参数函数以及多文件组织、编译预处置、工程文件的概念和运转库函数。置、工程文件的概念和运转库函数。 练习:编写程序,输入x,根据下面y和x的关系,计算y值并输出3x-11 (x10)x (x1)2x-1 (1xx; cinx; if(x1) y=x; if(x1) y=x; else if(1=x10) y=2 else if(1=x10) y=2* *x-1;x-1; else y=3 else y=3* *x-11;x-11; couty; coutx; cinx; if(x1) y=x; if(x1) y=x; else if(1=x&x
3、10) y=2 else if(1=x&x10) y=2* *x-1;x-1; else y=3 else y=3* *x-11;x-11; couty; coutx; cinx; if(x1) y=x; if(x1) y=x; else if(1x10) y=2 else if(1x10) y=2* *x-1;x-1; else y=3 else y=3* *x-11;x-11; couty; coutx; cinx; x=10?y=3x-11:y=2x-1 x=10?y=3x-11:y=2x-1 couty; coutx; cinx; if(x1) y=x; if(x1) y=x;
4、 else if(x10) y=2 else if(x10) y=2* *x-1;x-1; else y=3 else y=3* *x-11;x-11; couty; couty; 3.1 函数的定义与调用函数的定义与调用 3. 5 作用域与标识符的可见性作用域与标识符的可见性 3.4 函数调用机制函数调用机制 3.3 全局变量和部分变量全局变量和部分变量 3.2 函数的参数传送函数的参数传送,前往值及函数声明前往值及函数声明 3.10 编译预处置编译预处置 3.9 头文件与多文件构造头文件与多文件构造 3.6 存储类型与标识符的生命期存储类型与标识符的生命期 3.8 函数的一些高级议题函数的
5、一些高级议题 3.7 函数的递归调用函数的递归调用 3.1.1 函数概述函数概述3.1.2 函数的定义函数的定义3.1.3 函数的调用函数的调用 函数是函数是C+C+程序的根本组成模块。程序的根本组成模块。经过函数,可以把一个复杂义务分解成为假设经过函数,可以把一个复杂义务分解成为假设干个易于处理的小义务。充分表达逐渐细化的设计干个易于处理的小义务。充分表达逐渐细化的设计思想。思想。组成组成C+C+程序的假设干函数中,有一个称为程序的假设干函数中,有一个称为main()main()Winmain()Winmain()函数,是程序执行的入口,它可以调函数,是程序执行的入口,它可以调用其他函数,但
6、不可以被调用。而其他普通函数既可用其他函数,但不可以被调用。而其他普通函数既可以调用也可以被调用。以调用也可以被调用。函数概念的引入:函数概念的引入:入口函数:入口函数:main ( )fun2( )fun1( )fun3( )funa( )funb( )func( )图图3.1 3.1 函数调用层次关系函数调用层次关系3.1.1终了终了库函数和自定义函数:库函数和自定义函数: 库函数或规范函数,是由编译系统预定义库函数或规范函数,是由编译系统预定义的,如一些常用的数学计算函数、字符串处置的,如一些常用的数学计算函数、字符串处置函数、图形处置函数、规范输入输出函数等。函数、图形处置函数、规范输
7、入输出函数等。 库函数都按功能分类,集中阐明在不同的库函数都按功能分类,集中阐明在不同的头文件中。用户只需在本人的程序中包含某个头文件中。用户只需在本人的程序中包含某个头文件,就可直接运用该文件中定义的函数。头文件,就可直接运用该文件中定义的函数。 用户根据需求将某个具有相对独立功能的用户根据需求将某个具有相对独立功能的程序定义为函数,称自定义函数。程序定义为函数,称自定义函数。四个要素:四个要素:前往值类型,函数名,参数列表和函数体前往值类型,函数名,参数列表和函数体无参函数定义格式为:无参函数定义格式为: 函数名函数名()()函数体函数体 阐明:阐明: 数据类型指函数前往值类型,可以是任一
8、种数数据类型指函数前往值类型,可以是任一种数据类型。没有前往值应将前往值类型定义为据类型。没有前往值应将前往值类型定义为voidvoid。 函数名采用合法标识符表示。函数名采用合法标识符表示。 对无参函数,参数括号中的对无参函数,参数括号中的voidvoid通常省略,但通常省略,但括号不能省略。括号不能省略。 函数体由一系列语句组成。函数体可以为空,函数体由一系列语句组成。函数体可以为空,称为空函数。称为空函数。 例例: 打印一个表头打印一个表头void TableHead ( ) cout*endl;cout* example *endl;cout*endl;有参函数的定义格式为有参函数的定
9、义格式为函数名函数名 (参数类型参数类型1方式参数方式参数1函数体函数体 例例: 前往两个整数中较大一个的值前往两个整数中较大一个的值 int max (int a, int b) int x=a=b?a:b; return(x); 有参函数的参数表中列出一切方式参数的类型和参数称有参函数的参数表中列出一切方式参数的类型和参数称号。各参数即使类型一样也必需分别加以阐明。号。各参数即使类型一样也必需分别加以阐明。 方式参数简称形参,只能是变量名,不允许是常量或表方式参数简称形参,只能是变量名,不允许是常量或表达式。达式。 Why?int f()string s;.return s;f2(int
10、i).int f(int v1,int v2).double square(double x)return x*x;问题:定义函数时终究哪些变量该当作为函数的参数?问题:定义函数时终究哪些变量该当作为函数的参数?哪些该当定义在函数体内?哪些该当定义在函数体内?原那么:函数在运用时被看成原那么:函数在运用时被看成 “黑匣子,除了输黑匣子,除了输入输出外,其他部分可不用关怀。从函数的定义看出,入输出外,其他部分可不用关怀。从函数的定义看出,函数头正是用来反映函数的功能和运用接口,它所定函数头正是用来反映函数的功能和运用接口,它所定义的是义的是“做什么。即明确了做什么。即明确了“黑匣子的输入输出黑匣
11、子的输入输出部分,输出就是函数的前往值,输入就是参数。因此,部分,输出就是函数的前往值,输入就是参数。因此,只需那些功能上起自变量作用的变量才必需作为参数只需那些功能上起自变量作用的变量才必需作为参数定义在参数表中;函数体中详细描画定义在参数表中;函数体中详细描画“如何做,因如何做,因此除参数之外的为实现算法所需用的变量该当定义在此除参数之外的为实现算法所需用的变量该当定义在函数体内。函数体内。 C+ C+中不允许函数的嵌套定义,即在一个函数中中不允许函数的嵌套定义,即在一个函数中定义另一个函数。定义另一个函数。函数调用:函数调用: 所谓函数调用,就是使程序转去执行函所谓函数调用,就是使程序转
12、去执行函数体。数体。 在在C+C+中,除了主函数外,其他任何函数中,除了主函数外,其他任何函数都不能单独作为程序运转。任何函数功能的都不能单独作为程序运转。任何函数功能的实现都是经过被主函数直接或间接调用进展实现都是经过被主函数直接或间接调用进展的。的。 无参函数的调用格式:无参函数的调用格式: 函数名函数名( )( ) 有参函数的调用格式:有参函数的调用格式: 函数名函数名( (实践参数表实践参数表) )其中实践参数简称实参,用来将实践参数的其中实践参数简称实参,用来将实践参数的值传送给形参,因此可以是常量、具有值的值传送给形参,因此可以是常量、具有值的变量或表达式。变量或表达式。【例【例3
13、.1】 输入两个实数,输出其中较大的数输入两个实数,输出其中较大的数 函数的调用规那么1、调用函数时,函数名必需与调用途的函数名完全一致。2、实参的个数必需与形参的个数一致。3、函数必需先声明或定义,后调用。4、函数可以直接或间接地本人调用本人,称为递归调用。int main() int add(int x, int y); int a=100,b=200,c ; c =add(a,b); .int add (int x, int y ) int z ; z=x+y; return(z);错误:c=ad(a,b);c=add(a);int add(int , int ); 321 函数的参数传
14、送及传值调用函数的参数传送及传值调用 323 函数声明函数声明322 函数前往值函数前往值 参数传送:参数传送: 函数调用首先要进展参数传送,参数传函数调用首先要进展参数传送,参数传送的方向是由实参传送给形参。送的方向是由实参传送给形参。 传送过程是,先计算实参表达式的值,传送过程是,先计算实参表达式的值,再将该值传送给对应的形参变量。普通情况再将该值传送给对应的形参变量。普通情况下,实参和形参的个数和陈列顺序应一一对下,实参和形参的个数和陈列顺序应一一对应,并且对应参数应类型匹配赋值兼容应,并且对应参数应类型匹配赋值兼容, ,即实参的类型可以转化为形参类型。而对应即实参的类型可以转化为形参类
15、型。而对应参数的参数名那么不要求一样。参数的参数名那么不要求一样。传值调用和援用调用:传值调用和援用调用:按照参数方式的不同,按照参数方式的不同,C+有两种调用方式:有两种调用方式:传值调用和援用调用。传值调用传送的是实传值调用和援用调用。传值调用传送的是实参的值,本章引见传值调用。参的值,本章引见传值调用。在调用函数时,普通在主调函数和被调用函数之间有 信息传送 这是由函数中的参数来完成的。调用函数和被调用函数之间的参数传送实践参数实践参数 方式参数方式参数主调用函数中的参数被调用函数中的参数(实参实参)(形参形参)int main() int a=5,b=10, c ; c=max(a,b
16、); printf(“c=%dn, c); return 0;int max(int x, int y) int t; if (xy) t=x; else t=y; return(t); yxa5b10510ct101010int main() int a=5,b=10, c ; c=max(a,b); printf(“c=%dn, c); return 0; int max(int x, int y) int t; if (xy) t=x; else t=y; return(t); 信息传送原那信息传送原那么:实参到形么:实参到形参参单向值传送单向值传送特点:实参与形参各占用不同的内存单元传
17、值调用:传值调用:将实参的值复制给形参,在函数中将实参的值复制给形参,在函数中参与运算的是形参,而实参不会发参与运算的是形参,而实参不会发生任何改动。传值调用起了一种隔生任何改动。传值调用起了一种隔离作用。离作用。【例【例3.2】 实参和形参对应关系的例如。实参和形参对应关系的例如。留意:【例留意:【例1.3】中调用函数】中调用函数strcpy(s3, s2),却实现了字符数,却实现了字符数组组s2的内容复制到字符数组的内容复制到字符数组s3中。这是由于数组名实践中。这是由于数组名实践上代表存储数组的内存的首地址,复制给形参的是实参数上代表存储数组的内存的首地址,复制给形参的是实参数组的首地址
18、,结果参与运算的是实参数组。数组作为参数组的首地址,结果参与运算的是实参数组。数组作为参数,定义时形参用数组名加一对方括号,调用时实参只用数,定义时形参用数组名加一对方括号,调用时实参只用数组名组名 100aFFC2200bFFC4int add (int x, int y) int z ; z=(+x)+(+y) ; return(z); int main() int a=100,b=200,c ; c =add(a,b); coutcendl; return 0; 100 xFFA2200yFFA4101201302z1094302cFFC6 当形参值在函 数中发生变化时, 且不影响调用它
19、的 实参值的变化。 用途 采用这种数据复制的参数传送方式,每次每个参数只能传送一个数据。缺点add (a , b) ;int add ( x, y ) A) 11 B) 20 C) 21 D) 31请写出以下程序的运转结果 main() int x=6,y=7,z=8,r ; r=f (x-,y+,x+y),z-); coutr=rendl; int f ( int a, int b ) int c ; c=a+b; return(c); C) 21 课下作业 查找资料,如何向主函数main() 传送参数? 程序举例阐明。returnreturn语句的格式:语句的格式:return retur
20、n 表达式;表达式;函数的计算结果经过该语句传送回主调函函数的计算结果经过该语句传送回主调函数。数。【例【例3.3】设计函数,根据三角形的三边长求面】设计函数,根据三角形的三边长求面积。假设不能构成三角形,给出提示信息。积。假设不能构成三角形,给出提示信息。分析:函数为计算三角形面积,普通三角形前往分析:函数为计算三角形面积,普通三角形前往面积值,假设不能构成三角形那么前往面积值,假设不能构成三角形那么前往-1。设计。设计一个主函数完成函数测试。根据前往值情况输出一个主函数完成函数测试。根据前往值情况输出相应结果。相应结果。思索:表达式值的类型和思索:表达式值的类型和函数前往值类型关系?函数前
21、往值类型关系?函数可以有前往值,也可以没有前往值。对函数可以有前往值,也可以没有前往值。对于没有前往值的函数,功能只是完成一定操作,应于没有前往值的函数,功能只是完成一定操作,应将前往值类型定义为将前往值类型定义为void ,函数体内可以没有,函数体内可以没有return语句,当需求在程序指定位置退出时,可语句,当需求在程序指定位置退出时,可以在该处放置一个:以在该处放置一个: return ;讨论:讨论:3.2.2终了终了 函数声明是一条以分号终了的语句:函数声明是一条以分号终了的语句: 函数名函数名 ( (); 语法上对程序文件中函数的陈列次序要求满足先定义后语法上对程序文件中函数的陈列次
22、序要求满足先定义后运用。但从构造化程序设计的角度,通常是先调用后定义。运用。但从构造化程序设计的角度,通常是先调用后定义。运用函数声明,那么既符合由粗到精的思想方式,又满足运用函数声明,那么既符合由粗到精的思想方式,又满足了语法要求。了语法要求。 其中形参表可以逐个列出每个参数的类型和参数名,其中形参表可以逐个列出每个参数的类型和参数名,也可以列出每个形参的类型,参数名可省略,各形参之间也可以列出每个形参的类型,参数名可省略,各形参之间以逗号分隔。函数声明和所定义的函数必需在前往值类型、以逗号分隔。函数声明和所定义的函数必需在前往值类型、函数名、形参个数和类型及次序等方面完全对应一致,否函数名
23、、形参个数和类型及次序等方面完全对应一致,否那么将导致编译错误。那么将导致编译错误。 函数声明的引入:函数声明的引入:函数声明的格式:函数声明的格式:int max(int x, int y); /okint max(int,int); /okint max(int) /Xfloat max(int,int) /Xint max(int x, int y) int t; if (xy) t=x; else t=y; return(t); 下面是一个运用构造化程序设计思想开发的企业管理下面是一个运用构造化程序设计思想开发的企业管理报表程序的框架。它运用了函数声明。报表程序的框架。它运用了函数声明
24、。void menu_print();void account_report();void engineering_report();void marketing_report();int main() int choice; do menu_print();cinchoice; while(choice=4); switch(choice) case 1: account_report(); break; case 2: engineering_report(); break; case 3: marketing_report(); break; return 0;void menu_pri
25、nt() cout系统功能:系统功能:endl; cout1财务报表财务报表endl; cout2工程报表工程报表endl; cout3市场报表市场报表endl; cout选择业务序号:选择业务序号:; void account_report() /生成财务报表生成财务报表void engineering_report() /生成工程报表生成工程报表 void marketing_report() /生成市场报表;生成市场报表;【例【例3.4】 输出一切满足以下条件的正整数输出一切满足以下条件的正整数m:10m1000且且m、m2、m3均为回文数。均为回文数。分析:回文指左右对称的序列。如分析
26、:回文指左右对称的序列。如121、353等就是回等就是回文数。判别整数能否回文数用函数实现,其思想是将文数。判别整数能否回文数用函数实现,其思想是将该数各位拆开后反向组成新的整数,假设该整数与原该数各位拆开后反向组成新的整数,假设该整数与原数相等那么为回文数。数相等那么为回文数。m m*m m*m*m11 121 1331101 10201 1030301111 12321 7631 运转结果:运转结果: 332 全局变量 333 部分变量 自在存储区自在存储区 ( (动态数据动态数据) )栈区函数部分数据栈区函数部分数据main()函数部分数据函数部分数据全局数据区全局数据区( (全局、静态
27、全局、静态) )代码区程序代码代码区程序代码 操作系统为一个操作系统为一个C+C+程序的运转所分配的内存分为程序的运转所分配的内存分为四个区域,如图四个区域,如图3.3 3.3 所示:所示:存储区域阐明:存储区域阐明:1代码区代码区Code area:存放程序:存放程序代码,即程序中各个函数的代码块;代码,即程序中各个函数的代码块;2全局数据区全局数据区Data area:存放:存放全局数据和静态数据;分配该区时内存全全局数据和静态数据;分配该区时内存全部清零,结果变量的一切字节自动初始化部清零,结果变量的一切字节自动初始化为零。为零。3栈区栈区Stack area:存放部分变:存放部分变量,
28、如函数中的变量等;分配栈区时不处量,如函数中的变量等;分配栈区时不处置内存,即变量取随机值。置内存,即变量取随机值。4自在存储区自在存储区Free store area:存放与指针相关的动态数据。分配自在存存放与指针相关的动态数据。分配自在存储区时不处置内存。参见第七章。储区时不处置内存。参见第七章。在一切函数之外定义的变量称为全局变量。在一切函数之外定义的变量称为全局变量。全局变量在编译时建立在全局数据区,在未给全局变量在编译时建立在全局数据区,在未给出初始化值时系统自动初始化为全出初始化值时系统自动初始化为全0。全局变量可定义在程序开头,也可定义在中间全局变量可定义在程序开头,也可定义在中
29、间位置,该全局变量在定义处之后的任何位置都是可位置,该全局变量在定义处之后的任何位置都是可以访问的,称为可见的。以访问的,称为可见的。【例【例3.5】 多个函数运用全局变量的例子。多个函数运用全局变量的例子。全局变量引入:全局变量引入:定义在函数内或块内的变量称为部分变量。定义在函数内或块内的变量称为部分变量。程序中运用的绝大多数变量都是部分变量。程序中运用的绝大多数变量都是部分变量。部分变量在程序运转到它所在的块时建立在栈中,部分变量在程序运转到它所在的块时建立在栈中,该块执行终了部分变量占有的空间即被释放。该块执行终了部分变量占有的空间即被释放。部分变量在定义时可加修饰词部分变量在定义时可
30、加修饰词auto,但通常省略。,但通常省略。部分变量在定义时假设未初始化,其值为随机数。部分变量在定义时假设未初始化,其值为随机数。部分变量引入:部分变量引入:【例【例3.6】 运用部分变量的例子。运用部分变量的例子。思索:假设定义思索:假设定义一个对象一个对象/变量为变量为全局方式还是部全局方式还是部分方式?分方式? 1、主函数中定义的变量也只用在主函数中有效;关于部分变量运用的几点阐明 2、不同函数中可以运用一样的变量名,且它们代 表不同的存储单元,互不干扰; 3、方式参数也是部分变量。其它函数是不能调用 该形参的; 4、在一个函数内部,可以在复合语句中定义变量 ,这些变量只能在本复合语句
31、中有效。部分变量占用的内存是在程序执行过程中部分变量占用的内存是在程序执行过程中“动态地建立动态地建立和释放的。这种和释放的。这种“动态是经过栈由系统自动管理进展的。动态是经过栈由系统自动管理进展的。1建立栈空间;建立栈空间;6恢复现场:取主调函数运转形状及前往地址,释放栈空间;恢复现场:取主调函数运转形状及前往地址,释放栈空间;7继续主调函数后续语句。继续主调函数后续语句。5释放被调函数中部分变量占用的栈空间;释放被调函数中部分变量占用的栈空间;4执行被调函数函数体;执行被调函数函数体;3为被调函数中的部分变量分配空间,完成参数传送;为被调函数中的部分变量分配空间,完成参数传送;2维护现场:
32、主调函数运转形状和前往地址入栈;维护现场:主调函数运转形状和前往地址入栈;调用过程:调用过程:void fun1(int, int);void fun2(float);int main() int x=1;y=2; fun1(x, y); return 0;void fun1(int a,int b) float x=3; fun2(x);void fun2(float y) int x; x栈顶栈顶栈底栈底y3fun2()fun1()运行状态及返回地址运行状态及返回地址x3b2a1fun1()main()运行状态及返回地址运行状态及返回地址y2x1main()操作系统运行状态及返回地址操作系
33、统运行状态及返回地址此图例阐明在程序执行过程中怎样经过栈此图例阐明在程序执行过程中怎样经过栈“动态地建立和动态地建立和释放部分变量占用的内存的释放部分变量占用的内存的地址地址.0XFE8020X5984D0XFE1543 文件作用域文件作用域 2 函数声明作用域函数声明作用域 作用域:目的识符可以被运用的范围。只需在作作用域:目的识符可以被运用的范围。只需在作用域内标识符才可以被访问称为可见。用域内标识符才可以被访问称为可见。本节重点讨论部分域和文件域全局域,其中本节重点讨论部分域和文件域全局域,其中部分域包括块域和函数声明域。任何标识符作用域的部分域包括块域和函数声明域。任何标识符作用域的起
34、始点均为标识符阐明处。起始点均为标识符阐明处。下面分别引见:下面分别引见:1 块作用域块作用域 函数中定义的标识符,包括形参和函数体中定义函数中定义的标识符,包括形参和函数体中定义的部分变量,作用域都在该函数内,也称作函数域。的部分变量,作用域都在该函数内,也称作函数域。块指一对大括号括起来的程序段。块中定义的标块指一对大括号括起来的程序段。块中定义的标识符,作用域在块内。识符,作用域在块内。复合语句是一个块。复合语句是一个块。函数也是一个块。函数也是一个块。复合语句中定义的标识符,复合语句中定义的标识符,作用域仅在该复合语句中。作用域仅在该复合语句中。【例【例3.7】 输入两数,按从大到小的
35、顺序保管。输入两数,按从大到小的顺序保管。块的引入:块的引入:由由VC+平台运转,结果如下:平台运转,结果如下:输入两整数:输入两整数:3 5调用前:实参调用前:实参a=3,b=5调用中调用中交换前:形参交换前:形参a=3,b=5交换后:形参交换后:形参a=5,b=3调用后:实参调用后:实参a=3,b=5 交换失败交换失败部分变量具有部分作用域使得程序在不同块中可以部分变量具有部分作用域使得程序在不同块中可以运用同名变量。这些同名变量各自在本人的作用域运用同名变量。这些同名变量各自在本人的作用域中可见,在其它地方不可见。中可见,在其它地方不可见。【例【例3.8】设计函数完成两数交换,用主函数进
36、展测试。】设计函数完成两数交换,用主函数进展测试。 对于块中嵌套其它块的情况,假设嵌套块中有同名部分变量,服从部对于块中嵌套其它块的情况,假设嵌套块中有同名部分变量,服从部分优先原那么,即在内层块中屏蔽外层块中的同名变量,换句话说,内层分优先原那么,即在内层块中屏蔽外层块中的同名变量,换句话说,内层块中部分变量的作用域为内层块;外层块中部分变量的作用域为外层除去块中部分变量的作用域为内层块;外层块中部分变量的作用域为外层除去包含同名变量的内层块部分。包含同名变量的内层块部分。假设块内定义的部分变量与全局变量同名,块内依假设块内定义的部分变量与全局变量同名,块内依然部分变量优先,但与块作用域不同
37、的是,在块内然部分变量优先,但与块作用域不同的是,在块内可以经过域运算符可以经过域运算符“:访问同名的全局变量。访问同名的全局变量。【例【例3.9】 显示同名变量可见性。显示同名变量可见性。 函数声明不是定义函数,在作函数声明时,其中的形参作用域只在声明中,即作用域终了于右括号。正是由于形参不能被程序的其他地方援用,所以通常只需声明形参个数和类型,形参名可省略。文件作用域也称全局作用域。定义在一切函数之外的文件作用域也称全局作用域。定义在一切函数之外的标识符,具有文件作用域,作用域为从定义处到整个标识符,具有文件作用域,作用域为从定义处到整个源文件终了。文件中定义的全局变量和函数都具有文源文件
38、终了。文件中定义的全局变量和函数都具有文件作用域。件作用域。假设某个文件中阐明了具有文件作用域的标识符,该假设某个文件中阐明了具有文件作用域的标识符,该文件又被另一个文件包含,那么该标识符的作用域延文件又被另一个文件包含,那么该标识符的作用域延伸到新的文件中。如伸到新的文件中。如cincin和和coutcout是在头文件是在头文件iostreamiostream中阐中阐明的具有文件作用域的标识符,它们的作用域也延伸明的具有文件作用域的标识符,它们的作用域也延伸到嵌入到嵌入iostreamiostream的文件中。的文件中。存储类型存储类型storage class决议标识符的存储决议标识符的存
39、储区域,即编译系统在不同区域为不同存储类型的标区域,即编译系统在不同区域为不同存储类型的标识符分配空间。由于存储区域不同,标识符的生命识符分配空间。由于存储区域不同,标识符的生命期也不同。所谓生命期,指的是标识符从获得空间期也不同。所谓生命期,指的是标识符从获得空间到空间释放之间的期间,标识符只需在生存期中、到空间释放之间的期间,标识符只需在生存期中、并且在其本人的作用域中才干被访问。并且在其本人的作用域中才干被访问。 3.3.2 生命期 自动变量为用自动变量为用auto阐明的变量,通常阐明的变量,通常auto缺省。部分变量都是自缺省。部分变量都是自动变量,生命期开场于块的执行,终了于块的终了
40、,其缘动变量,生命期开场于块的执行,终了于块的终了,其缘由是自动变量的空间分配在栈中,块开场执行时系统自动由是自动变量的空间分配在栈中,块开场执行时系统自动分配空间,块执行终了时系统自动释放空间。故自动变量分配空间,块执行终了时系统自动释放空间。故自动变量的生命期和作用域是一致的。的生命期和作用域是一致的。为提高程序运转效率,可以将某些变量保管在存放器中,即用为提高程序运转效率,可以将某些变量保管在存放器中,即用register阐明为存放器变量,但不提倡运用。阐明为存放器变量,但不提倡运用。C+中关于存储类型的阐明符中关于存储类型的阐明符storage class specifier有四有四个
41、:个:auto、register、static和和extern。其中用。其中用auto和和register修修饰的称为自动存储类型,用饰的称为自动存储类型,用static修饰的称为静态存储类型,修饰的称为静态存储类型,用用extern修饰的称为外部存储类型。修饰的称为外部存储类型。1 1 自动存储类型自动存储类型static阐明的变量称为静态变量。根据定义的位置不同,还阐明的变量称为静态变量。根据定义的位置不同,还分为部分静态变量和全局静态变量,也称内部静态变量和外部分为部分静态变量和全局静态变量,也称内部静态变量和外部静态变量。静态变量均存储在全局数据区,假设程序未显式给静态变量。静态变量均
42、存储在全局数据区,假设程序未显式给出初始化值,系统自动初始化为全出初始化值,系统自动初始化为全0,且初始化只进展一次;静,且初始化只进展一次;静态变量占有的空间要到整个程序执行终了才释放,故静态变量态变量占有的空间要到整个程序执行终了才释放,故静态变量具有全局生命期。具有全局生命期。部分静态变量是定义在块中的静态变量,当块第一次被执行时,部分静态变量是定义在块中的静态变量,当块第一次被执行时,编译系统在全局数据区为其开辟空间并保管数据,该空间不断编译系统在全局数据区为其开辟空间并保管数据,该空间不断到整个程序终了才释放。部分静态变量具有部分作用域,但却到整个程序终了才释放。部分静态变量具有部分
43、作用域,但却具有全局生命期。具有全局生命期。【例【例3.10】 自动变量与部分静态变量的区别自动变量与部分静态变量的区别 int f( int a) auto int b=0; static int c=3; b=b+1;c=c+1; return(a+b+c); int main() int a=2, i ; for(i=0; i 3; i +) cout f(a)endl; 0b3c1举举例例2a2a4701580691 fun(int a, int b) static int m, i=2; i+=m+1; m=i+a+b; return(m); int main() int k=4,m
44、=1,p; p=fun(k,m); coutpendl; p=fun(k,m); coutpendl; 0m4k4a1m1b p2i388120178 17817int main() fun(); fun(); void fun() static int a3=0,1,2; int i ; for(i =0; i 3; i +) ai +=ai ; for(i =0; i 3; i +) coutai ; coutendl; return; 0 12 a0 a1 a2024048一个一个C+程序可以由多个源程序文件组成。多文件程序系统可程序可以由多个源程序文件组成。多文件程序系统可以经过外部存
45、储类型的变量和函数来共享某些数据和操作。以经过外部存储类型的变量和函数来共享某些数据和操作。在一个程序文件中定义的全局变量和函数缺省为外部的,即其作在一个程序文件中定义的全局变量和函数缺省为外部的,即其作用域可以延伸到程序的其他文件中。其他文件假设要运用这个文用域可以延伸到程序的其他文件中。其他文件假设要运用这个文件中定义的全局变量和函数,应该在运用前用件中定义的全局变量和函数,应该在运用前用“extern作外部作外部声明。外部声明通常放在文件的开头函数总是省略声明。外部声明通常放在文件的开头函数总是省略extern。外部变量声明不同于全局变量定义,变量定义时编译器为其分外部变量声明不同于全局
46、变量定义,变量定义时编译器为其分配存储空间,而变量声明那么表示该全局变量已在其他地方定配存储空间,而变量声明那么表示该全局变量已在其他地方定义过,编译系统不再分配存储空间。义过,编译系统不再分配存储空间。外部的全局变量或函数加上外部的全局变量或函数加上static修饰,就成为静态全局变量修饰,就成为静态全局变量或静态函数。静态的全局变量和函数作用域限制在本文件,其或静态函数。静态的全局变量和函数作用域限制在本文件,其他文件即使运用外部声明也无法运用该全局变量或函数。他文件即使运用外部声明也无法运用该全局变量或函数。 【例【例3.11】外部存储类型的例子】外部存储类型的例子全局变量的static
47、:假设程序是由多个源文件组成时,此全局变量的作用域只限于本文件中。extern int x; int x;main() a1.cppstatic char cc; extern int x; a2.cpp extern char cc; a3.cpp1. 1. 静态生命期静态生命期 静态生命期静态生命期Static extent或或Static storage duration指指的是标识符从程序开场运转时就存在,具有存储空间,到程的是标识符从程序开场运转时就存在,具有存储空间,到程序运转终了时消亡,释放存储空间。具有静态生命期的标识序运转终了时消亡,释放存储空间。具有静态生命期的标识符存放在
48、全局数据区,如全局变量、静态全局变量、静态部符存放在全局数据区,如全局变量、静态全局变量、静态部分变量。具有静态生命期的标识符在未被用户初始化的情况分变量。具有静态生命期的标识符在未被用户初始化的情况下,系统会自动将其初始化为下,系统会自动将其初始化为0。 函数驻留在代码区,也具有静态生命期。一切具有文件函数驻留在代码区,也具有静态生命期。一切具有文件作用域的标识符都具有静态生命期。作用域的标识符都具有静态生命期。2. 2. 部分生命期部分生命期 在函数内部或块中定义的标识符具有部分生命期在函数内部或块中定义的标识符具有部分生命期Automatic extent或或Automatic stor
49、age duration,其生命期开,其生命期开场于执行到该函数或块的标识符定义处,终了于该函数或块的场于执行到该函数或块的标识符定义处,终了于该函数或块的终了处。具有部分生命期的标识符存放在栈区。具有部分生命终了处。具有部分生命期的标识符存放在栈区。具有部分生命期的标识符假设未被初始化,其内容是随机的,不可援用。期的标识符假设未被初始化,其内容是随机的,不可援用。 具有部分生命期的标识符必定具有部分作用域;但反之不具有部分生命期的标识符必定具有部分作用域;但反之不然,静态部分变量具有部分作用域,但却具有静态生命期。然,静态部分变量具有部分作用域,但却具有静态生命期。具有动态生命期具有动态生命
50、期dynamic extent或或dynamic storage duration的标识符存放在自在存储区,的标识符存放在自在存储区,由特定的函数调用或运算来创建和释放,如用由特定的函数调用或运算来创建和释放,如用new运算符或调用运算符或调用malloc()函数为变量分配函数为变量分配存储空间时,变量的生命期开场,而用存储空间时,变量的生命期开场,而用delete运运算符或调用算符或调用free()函数释放空间或程序终了函数释放空间或程序终了时,变量生命期终了。关于时,变量生命期终了。关于new运算符和运算符和delete运算符将在第七章中引见。运算符将在第七章中引见。3. 3. 动态生命期
51、动态生命期1n 1)!-(n*n1n 1 0n 1 n! 递归是一种描画问题的方法,或称算法。递递归是一种描画问题的方法,或称算法。递归的思想可以简单地描画为归的思想可以简单地描画为“本人调用本人。本人调用本人。例如用如下方法定义阶乘:例如用如下方法定义阶乘:可以看出是用阶乘定义阶乘,这种本人定义可以看出是用阶乘定义阶乘,这种本人定义本人的方法称为递归定义。本人的方法称为递归定义。递归的引入:递归的引入:递归定义的阶乘函数:递归定义的阶乘函数:fac(int n)if (n=0|n=1) return 1;else return n*fac(n-1);只需设计主函数调用阶乘函数,即可实现计算阶
52、乘。只需设计主函数调用阶乘函数,即可实现计算阶乘。【例【例3.12】 求求4!运转结果:运转结果:4321126244!=24阐明:阐明:coutn4!=fac(4)endl;执行时是先算函数值,然后再从左到右输出各表达式的值。执行时是先算函数值,然后再从左到右输出各表达式的值。所以有两行输出,而不是第一行插在第二行赋值号与所以有两行输出,而不是第一行插在第二行赋值号与24之间。之间。讨论:讨论:计算是先右后左。请看下一条输出语句:计算是先右后左。请看下一条输出语句:coutn4!=fac(4) n3!=fac(3)=0&ch=9?1:0;int main() char ch; whi
53、le(cin.get(ch), ch!= n) if (IsNumber(ch) cout是数字字符是数字字符 endl; else cout不是数字字符不是数字字符 endl; return 0;因运用频度很高,阐明为内联函数。因运用频度很高,阐明为内联函数。3.9.1 头文件头文件规范库头文件:规范库头文件:思索标识符在其他文件中的可见性。运用头文件是很思索标识符在其他文件中的可见性。运用头文件是很有效的方法。如:有效的方法。如:#includeusing namespace std; 其中的其中的iostream是在规范名字空间域是在规范名字空间域std中定义的头中定义的头文件。对应的传
54、统方式的文件名为文件。对应的传统方式的文件名为,头文件以头文件以“.h为后缀。为后缀。 系统定义的头文件中定义了一些常用的公用标识系统定义的头文件中定义了一些常用的公用标识符和函数,用户只需将头文件包含进本人的文件,就符和函数,用户只需将头文件包含进本人的文件,就可使头文件中定义的标识符在用户文件中变得可见,可使头文件中定义的标识符在用户文件中变得可见,也就可以直接运用头文件中定义的标识符和函数。也就可以直接运用头文件中定义的标识符和函数。 自定义头文件:自定义头文件:除了系统定义的头文件外,用户还可以自定义除了系统定义的头文件外,用户还可以自定义头文件。对于具有外部存储类型的标识符,可头文件
55、。对于具有外部存储类型的标识符,可以在其他任何一个源程序文件中经声明后援用以在其他任何一个源程序文件中经声明后援用,因此用户完全可以将一些具有外部存储类型,因此用户完全可以将一些具有外部存储类型的标识符的声明放在一个头文件中。详细地说的标识符的声明放在一个头文件中。详细地说,头文件中可以包括:用户构造的数据类型,头文件中可以包括:用户构造的数据类型如枚举类型,外部变量,外部函数、常量和如枚举类型,外部变量,外部函数、常量和内联函数等具有一定通用性或常用的量,而普内联函数等具有一定通用性或常用的量,而普通性的变量和函数定义不宜放在头文件中。通性的变量和函数定义不宜放在头文件中。 在开发较大程序时
56、,通常将其分解为多个源程序文件在开发较大程序时,通常将其分解为多个源程序文件,每个较小的程序用一个源程序文件建立。程序经过建立,每个较小的程序用一个源程序文件建立。程序经过建立、编译、衔接,成为一个完好的可执行程序。多文件构造、编译、衔接,成为一个完好的可执行程序。多文件构造经过工程进展管理,在工程中建立假设干用户定义的头文经过工程进展管理,在工程中建立假设干用户定义的头文件件.h和源程序文件和源程序文件.cpp。头文件中定义用户自定义的数据。头文件中定义用户自定义的数据类型,一切的程序实现那么放在不同的源程序文件中。编类型,一切的程序实现那么放在不同的源程序文件中。编译时每个源程序文件单独编
57、译,假设源程序文件中有编译译时每个源程序文件单独编译,假设源程序文件中有编译预处置指令,那么首先经过编译预处置生成暂时文件存放预处置指令,那么首先经过编译预处置生成暂时文件存放在内存,之后对暂时文件进展编译生成目的文件在内存,之后对暂时文件进展编译生成目的文件.obj,编,编译后暂时文件撤销。一切的目的文件经衔接器衔接最终生译后暂时文件撤销。一切的目的文件经衔接器衔接最终生成一个完好的可执行文件成一个完好的可执行文件.exe。 图图3.11是一个多文件系统的开发过程。是一个多文件系统的开发过程。编译 预编译预编译编译 预编译预编译 预编译预编译编译图图3.11 C+程序开发过程程序开发过程fi
58、le1.hfile1.cppfile2.hfile2.cppfilen.hfilen.cpp暂时文件暂时文件1暂时文件暂时文件2暂时文件暂时文件nfile1.objfile2.objfilen.objFilename.exe.libC+规范类库规范类库衔接衔接运转运转3.10.1 宏定义指令宏定义指令 3.10.2 文件包含指令文件包含指令 3.10.3 条件编译指令条件编译指令 1 1 不带参宏定义不带参宏定义用来产生与一个字符串对应的常量字符串,格用来产生与一个字符串对应的常量字符串,格式为:式为:#define #define 宏名宏名 常量串常量串 预处置后文件中凡出现该字符串处均用其
59、对应预处置后文件中凡出现该字符串处均用其对应的常量串替代。交换过程称为宏交换或宏展开。的常量串替代。交换过程称为宏交换或宏展开。例如,假设运用指令例如,假设运用指令#define PI 3.1415926#define PI 3.1415926那么程序中可以运用标识符那么程序中可以运用标识符PIPI,编译预处置后,编译预处置后产生一个中间文件,文件中一切产生一个中间文件,文件中一切PIPI被交换为被交换为3.14159263.1415926。宏交换只是字符串和标识符之间的简单交换,宏交换只是字符串和标识符之间的简单交换,预处置本身不做任何数据类型和合法性检查,预处置本身不做任何数据类型和合法性
60、检查,也不分配内存单元。也不分配内存单元。2 2 带参数的宏定义带参数的宏定义带参宏定义的方式很象定义一个函数,格式为带参宏定义的方式很象定义一个函数,格式为:#define #define 宏名宏名 形参表形参表 表达式串表达式串 例如作如下宏定义:例如作如下宏定义:#define S(a,b) (a)#define S(a,b) (a)* *(b)/2(b)/2程序中可运用程序中可运用S(a,b)S(a,b),预处置后产生中间文件,预处置后产生中间文件,其中,其中S(a,b)S(a,b)被交换成被交换成(a)(a)* *(b)/2(b)/2。留意,宏定。留意,宏定义时形参通常要用括号括起来,否那么容易导义时形参
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 胶合板生产安全与职业健康考核试卷
- 电机在云计算数据中心的应用考核试卷
- 企业法律法规与政策环境考核试卷
- 2025合同丢失证明模板
- 2025风力发电站专业运维服务合同
- 肇庆市实验中学高二上学期期中考试化学(文)试题
- 2025届安徽省合肥市高三下学期期中考试四校联合调研历史试题(含答案)
- 酒店抵押合同书简单模板二零二五年
- 展位合作合同书协议书范例
- 社交媒体营销合同书二零二五年
- 浙江省宁波市余姚市2024年中考英语模拟试题(含答案)
- 服务质量保障措施方案
- 机场能源管理
- 高速公路路基及土石方工程施工方案与技术措施
- 技能人才评价新职业考评员培训在线考试(四川省)
- AQ 1083-2011 煤矿建设安全规范 (正式版)
- 河南省开封市铁路中学2023-2024学年八年级下学期6月期末历史试题
- CJT165-2002 高密度聚乙烯缠绕结构壁管材
- 驾驶员交通安全培训及考试试题
- 3货物接取送达运输协议
- DZ∕T 0148-2014 水文水井地质钻探规程(正式版)
评论
0/150
提交评论