《第三章函数精选文档.ppt》由会员分享,可在线阅读,更多相关《第三章函数精选文档.ppt(90页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第三章函数第三章函数本讲稿第一页,共九十页第三章第三章 函数函数 3.1 函数的定义与调用 3.5 作用域与标识符的可见性 3.4 函数调用机制 3.3 全局变量和局部变量 3.2 函数的参数传递,返回值及函数声明 3.10 编译预处理 3.9 头文件与多文件结构 3.6 存储类型与标识符的生命期 3.8 函数的一些高级议题 3.7 函数的递归调用 本讲稿第二页,共九十页 3.1 函数的定义与调用函数的定义与调用3.1.1 函数概述函数概述3.1.2 函数的定义函数的定义3.1.3 函数的调用函数的调用 本讲稿第三页,共九十页3.1.1 函数概述函数概述函数是函数是C+C+程序的基本组成模块。
2、程序的基本组成模块。通通过过函函数数,可可以以把把一一个个复复杂杂任任务务分分解解成成为为若若干干个个易易于于解解决的小任务。充分体现逐步细化的设计思想。决的小任务。充分体现逐步细化的设计思想。组组 成成 C+C+程程 序序 的的 若若 干干 函函 数数 中中,有有 一一 个个 称称 为为main()main()(Winmain()Winmain())函函数数,是是程程序序执执行行的的入入口口,它它可可以以调调用用其其他他函函数数,但但不不可可以以被被调调用用。而而其其他他一一般般函函数数既既可可以以调用也可以被调用。调用也可以被调用。函数概念的引入:函数概念的引入:入口函数:入口函数:本讲稿
3、第四页,共九十页3.1.1 函数概述函数概述main()fun2()fun1()fun3()funa()funb()func()图图3.1 3.1 函数调用层次关系函数调用层次关系本讲稿第五页,共九十页3.1.1 函数概述函数概述3.1.1结束结束库函数和自定义函数:库函数和自定义函数:库函数库函数或或标准函数标准函数,是由编译系统预定义的,如一些,是由编译系统预定义的,如一些常用的数学计算函数、字符串处理函数、图形处理函数、标常用的数学计算函数、字符串处理函数、图形处理函数、标准输入输出函数等。准输入输出函数等。库函数都按功能分类,集中说明在不同的头文件中库函数都按功能分类,集中说明在不同的
4、头文件中。用户只需在自己的程序中包含某个头文件,就可直接使用该用户只需在自己的程序中包含某个头文件,就可直接使用该文件中定义的函数。文件中定义的函数。用户根据需要将某个具有相对独立功能的程序定义用户根据需要将某个具有相对独立功能的程序定义为函数,称为函数,称自定义函数自定义函数。本讲稿第六页,共九十页3.1.2 函数的定义函数的定义无参函数定义格式为:无参函数定义格式为:数据类型函数名数据类型函数名(voidvoid)函数体函数体 说明:说明:数数据据类类型型指指函函数数返返回回值值类类型型,可可以以是是任任一一种种数数据据类类型型,默默认认为为返返回回整整型型值值(但但新新标标准准要要求求写
5、写明明,不不用用默默认认方方式式)。没没有有返返回回值应将返回值类型定义为值应将返回值类型定义为voidvoid。函数名采用合法标识符表示。函数名采用合法标识符表示。对无参函数,参数括号中的对无参函数,参数括号中的voidvoid通常省略,但括号不能省略。通常省略,但括号不能省略。函数体由一系列语句组成。函数体可以为空,称为空函数。函数体由一系列语句组成。函数体可以为空,称为空函数。1 1 无参函数无参函数本讲稿第七页,共九十页3.1.2 函数的定义函数的定义例例:打印一个表头打印一个表头void TableHead()cout*endl;cout*example *endl;cout*=b?
6、a:b);有参函数的参数表中列出所有有参函数的参数表中列出所有形式参数形式参数的类型和参数名称。各的类型和参数名称。各参数即使类型相同也必须分别加以说明。参数即使类型相同也必须分别加以说明。形式参数简称形参,形式参数简称形参,只能是变量名只能是变量名,不允许是常量或表达式。,不允许是常量或表达式。本讲稿第九页,共九十页问题:问题:定义函数时究竟哪些变量应当作为函数的参数?哪些应当定义函数时究竟哪些变量应当作为函数的参数?哪些应当定义在函数体内?定义在函数体内?原则原则:函数在使用时被看成函数在使用时被看成“黑匣子黑匣子”,除了输入输出外,其他部,除了输入输出外,其他部分可不必关心分可不必关心。
7、从函数的定义看出,函数头正是用来反映函数的功能。从函数的定义看出,函数头正是用来反映函数的功能和使用接口,它所定义的是和使用接口,它所定义的是“做什么做什么”。即明确了。即明确了“黑匣子黑匣子”的输入的输入输出部分,输出部分,输出就是函数的返回值,输入就是参数输出就是函数的返回值,输入就是参数。因此,只有那。因此,只有那些功能上起自变量作用的变量才必须作为参数定义在参数表中;函些功能上起自变量作用的变量才必须作为参数定义在参数表中;函数体中具体描述数体中具体描述“如何做如何做”,因此除参数之外的为实现算法所需用的,因此除参数之外的为实现算法所需用的变量应当定义在函数体内。变量应当定义在函数体内
8、。C+C+中不允许函数的嵌套定义,即在一个函数中定义另一个函数。中不允许函数的嵌套定义,即在一个函数中定义另一个函数。提示提示本讲稿第十页,共九十页3.1.3 函数的调用函数的调用函数调用:函数调用:所谓函数调用,就是使程序转去执行函数体。所谓函数调用,就是使程序转去执行函数体。在在C+C+中中,除除了了主主函函数数外外,其其他他任任何何函函数数都都不不能能单单独独作作为为程程序序运运行行。任任何何函函数数功功能能的的实实现现都都是是通通过过被被主主函函数数直直接接或或间间接接调调用进行的。用进行的。无参函数的调用格式:无参函数的调用格式:函数名函数名()()有参函数的调用格式:有参函数的调用
9、格式:函数名函数名(实际参数表实际参数表)其其中中实实际际参参数数简简称称实实参参,用用来来将将实实际际参参数数的的值值传传递递给给形形参参,因因此此可可以是常量、具有值的变量或表达式以是常量、具有值的变量或表达式。【例【例3.1】输入两个实数,输出其中较大的数输入两个实数,输出其中较大的数本讲稿第十一页,共九十页3.2 函数的参数传递、返回值及函数的参数传递、返回值及函数声明函数声明 321 函数的参数传递及传值调用 323 函数声明322 函数返回值 本讲稿第十二页,共九十页参数传递:参数传递:函数调用首先要进行参数传递,参数传递的方向是函数调用首先要进行参数传递,参数传递的方向是由实参传
10、递由实参传递给形参给形参。传递过程是,传递过程是,先计算实参表达式的值,再将该值传递给对应的先计算实参表达式的值,再将该值传递给对应的形参变量形参变量。一般情况下,。一般情况下,实参和形参的个数和排列顺序应一一实参和形参的个数和排列顺序应一一对应,并且对应参数应类型匹配对应,并且对应参数应类型匹配(赋值兼容)(赋值兼容),即实参的类型即实参的类型可以转化为形参类型。而对应参数的参数名则不要求相同。可以转化为形参类型。而对应参数的参数名则不要求相同。3.2.1 函数的参数传递及传值调用函数的参数传递及传值调用 传值调用和引用调用:传值调用和引用调用:按照参数形式的不同,按照参数形式的不同,C+有
11、两种调用方式:有两种调用方式:传值调用传值调用和和引用调用引用调用。传值调用传递的是实参的值,本章介绍传值调用。传值调用传递的是实参的值,本章介绍传值调用。本讲稿第十三页,共九十页 3.2.1 函数的参数传递及传值调用函数的参数传递及传值调用 传值调用:传值调用:将实参的值复制给形参,在函数中参加运算的是形参,将实参的值复制给形参,在函数中参加运算的是形参,而实参不会发生任何改变。传值调用起了一种隔离作而实参不会发生任何改变。传值调用起了一种隔离作用。用。【例【例3.2】实参和形参对应关系的示例。实参和形参对应关系的示例。注意:注意:【例【例1.3】中调用函数】中调用函数strcpy(s3,s
12、2),却实现了字符数组,却实现了字符数组s2的的内容复制到字符数组内容复制到字符数组s3中。这是因为数组名实际上代表存储数组的中。这是因为数组名实际上代表存储数组的内存的首地址,复制给形参的是实参数组的首地址,结果参加运算内存的首地址,复制给形参的是实参数组的首地址,结果参加运算的是实参数组。数组作为参数,定义时形参用数组名加一对方括号,的是实参数组。数组作为参数,定义时形参用数组名加一对方括号,调用时实参只用数组名调用时实参只用数组名 本讲稿第十四页,共九十页3.2.2 函数返回值函数返回值returnreturn语句的格式:语句的格式:return 表达式;表达式;函数的计算结果通过该语句
13、传递回主调函数。函数的计算结果通过该语句传递回主调函数。【例【例3.3】设计函数,根据三角形的三边长求面积。如果不设计函数,根据三角形的三边长求面积。如果不能构成三角形,给出提示信息。能构成三角形,给出提示信息。分析:函数为计算三角形面积,一般三角形分析:函数为计算三角形面积,一般三角形返回面积值返回面积值,若,若不能构成三角形则不能构成三角形则返回返回-1。设计一个主函数完成函数测试。根据。设计一个主函数完成函数测试。根据返回值情况输出相应结果。返回值情况输出相应结果。本讲稿第十五页,共九十页3.2.2 函数返回值函数返回值函函数数可可以以有有返返回回值值,也也可可以以没没有有返返回回值值。
14、对对于于没没有有返返回回值值的的函函数数,功功能能只只是是完完成成一一定定操操作作,应应将将返返回回值值类类型型定定义义为为void,函函数数体体内内可可以以没没有有return语语句句,当需要在程序指定位置退出时,可以在该处放置一个:当需要在程序指定位置退出时,可以在该处放置一个:return;讨论:讨论:3.2.2结束结束本讲稿第十六页,共九十页3.2.3 函数声明函数声明 函数声明是一条以分号结束的语句:函数声明是一条以分号结束的语句:函数返回值类型函数名函数返回值类型函数名(形参表形参表);语语法法上上对对程程序序文文件件中中函函数数的的排排列列次次序序要要求求满满足足先先定定义义后后
15、使使用用。但但从从结结构构化化程程序序设设计计的的角角度度,通通常常是是先先调调用用后后定定义义。使使用用函函数数声声明,则既符合由粗到精的思维方式,又满足了语法要求。明,则既符合由粗到精的思维方式,又满足了语法要求。其中形参表可以逐个列出每个参数的类型和参数名,也其中形参表可以逐个列出每个参数的类型和参数名,也可以列出每个形参的类型,可以列出每个形参的类型,参数名可省略参数名可省略,各形参之间以逗,各形参之间以逗号分隔。函数声明和所定义的函数必须在返回值类型、函数号分隔。函数声明和所定义的函数必须在返回值类型、函数名、形参个数和类型及名、形参个数和类型及次序次序等方面完全对应一致,否则将导致
16、等方面完全对应一致,否则将导致编译错误。编译错误。函数声明的引入:函数声明的引入:函数声明的格式:函数声明的格式:本讲稿第十七页,共九十页 下下面面是是一一个个使使用用结结构构化化程程序序设设计计思思想想开开发发的的企企业业管管理理报报表表程程序序的的框架。它使用了框架。它使用了函数声明函数声明。void menu_print();void account_report();void engineering_report();void marketing_report();int main()int choice;do menu_print();cinchoice;while(choice=4
17、);switch(choice)case 1:account_report();break;case 2:engineering_report();break;case 3:marketing_report();break;return 0;本讲稿第十八页,共九十页void menu_print()cout”系统功能:系统功能:”endl;cout”1财务报表财务报表”endl;cout”2工程报表工程报表”endl;cout”3市场报表市场报表”endl;cout”选择业务序号:选择业务序号:”;void account_report()/生成财务报表生成财务报表void engineeri
18、ng_report()/生成工程报表生成工程报表 void marketing_report()/生成市场报表;生成市场报表;本讲稿第十九页,共九十页3.2.3 函数声明函数声明【例例3.4】输输 出出 所所 有有 满满 足足 下下 列列 条条 件件 的的 正正 整整 数数m:10m1000且且m、m2、m3均为回文数。均为回文数。分析:分析:回文指左右对称的序列。如回文指左右对称的序列。如121、353等就是回文数。判等就是回文数。判断整数是否回文数用函数实现,其思想是将该数各位拆开后反断整数是否回文数用函数实现,其思想是将该数各位拆开后反向组成新的整数,如果该整数与原数相等则为回文数。向组
19、成新的整数,如果该整数与原数相等则为回文数。m m*m m*m*m11 121 1331101 10201 1030301111 12321 1367631 运行结果:运行结果:本讲稿第二十页,共九十页3.3 全局变量和局部变量全局变量和局部变量3 33 31 1 变量的存储机制与变量的存储机制与变量的存储机制与变量的存储机制与C+C+的内存布局的内存布局的内存布局的内存布局 3 33 32 2 全局变量全局变量全局变量全局变量 3 33 33 3 局部变量局部变量局部变量局部变量 本讲稿第二十一页,共九十页3.3.1 变量的存储机制与变量的存储机制与C+的内存布局的内存布局自由存储区自由存储
20、区(动态数据动态数据)栈区(函数局部数据)栈区(函数局部数据)(main()main()函数局部数据)函数局部数据)全局数据区全局数据区(全局、静态全局、静态)代码区(程序代码)代码区(程序代码)操操作作系系统统为为一一个个C+C+程程序序的的运运行行所所分分配配的的内内存存分分为为四个区域,如图四个区域,如图3.33.3 所示:所示:本讲稿第二十二页,共九十页存储区域说明:存储区域说明:(1)代码区()代码区(Code area):存放程序代码,即程序中各个函):存放程序代码,即程序中各个函数的代码块;数的代码块;(2)全局数据区()全局数据区(Data area):存放全局数据和静态数据;
21、):存放全局数据和静态数据;分配该区时内存全部清零分配该区时内存全部清零,结果变量的所有字节自动初始化为,结果变量的所有字节自动初始化为零。零。(3)栈区()栈区(Stack area):存放局部变量,如函数中的变量等;):存放局部变量,如函数中的变量等;分配栈区时不处理内存分配栈区时不处理内存,即变量取随机值。,即变量取随机值。(4)自由存储区(自由存储区(Free store area):):存放与指针相关的存放与指针相关的动态数据。动态数据。分配分配自由存储自由存储区时不处理内存区时不处理内存。参见第七章。参见第七章。3.3.1 变量的存储机制与变量的存储机制与C+的内存布局的内存布局本
22、讲稿第二十三页,共九十页 3.3.2 全局变量全局变量 在所有函数之外定义的变量称为在所有函数之外定义的变量称为全局变量全局变量。全全局局变变量量在在编编译译时时建建立立在在全全局局数数据据区区,在在未未给给出出初始化值时系统自动初始化值时系统自动初始化为全初始化为全0。全全局局变变量量可可定定义义在在程程序序开开头头,也也可可定定义义在在中中间间位位置置,该该全全局局变变量量在在定定义义处处之之后后的的任任何何位位置置都都是是可可以以访访问问的的,称为可见的。称为可见的。【例【例3.5】多个函数使用全局变量的例子。多个函数使用全局变量的例子。全局变量引入:全局变量引入:本讲稿第二十四页,共九
23、十页3.3.3 局部变量局部变量 定义在函数内或块内的变量称为定义在函数内或块内的变量称为局部变量局部变量。程序中使用的绝大多数变量都是局部变量。程序中使用的绝大多数变量都是局部变量。局局部部变变量量在在程程序序运运行行到到它它所所在在的的块块时时建建立立在在栈栈中中,该该块执行完毕局部变量占有的空间即被释放。块执行完毕局部变量占有的空间即被释放。局局部部变变量量在在定定义义时时可可加加修修饰饰词词auto,但但通通常常省省略略。局局部变量在定义时若未初始化,其值为随机数。部变量在定义时若未初始化,其值为随机数。局部变量引入:局部变量引入:【例【例3.6】使用局部变量的例子。使用局部变量的例子
24、。本讲稿第二十五页,共九十页3.4 函数调用机制函数调用机制 局局部部变变量量占占用用的的内内存存是是在在程程序序执执行行过过程程中中“动动态态”地地建建立立和和释释放放的。这种的。这种“动态动态”是通过栈由系统自动管理进行的。是通过栈由系统自动管理进行的。(1)建立栈空间;)建立栈空间;(6)恢复现场:取主调函数运行状态及返回地址,释放栈空间;)恢复现场:取主调函数运行状态及返回地址,释放栈空间;(7)继续主调函数后续语句。)继续主调函数后续语句。(5)释放被调函数中局部变量占用的栈空间;)释放被调函数中局部变量占用的栈空间;(4)执行被调函数函数体;)执行被调函数函数体;(3)为被调函数中
25、的局部变量分配空间,完成参数传递;)为被调函数中的局部变量分配空间,完成参数传递;(2)保护现场:主调函数运行状态和返回地址入栈;)保护现场:主调函数运行状态和返回地址入栈;调用过程:调用过程:本讲稿第二十六页,共九十页3.4 函数调用机制函数调用机制 void fun1(int,int);void fun2(float);int main()int x=1;y=2;fun1(x,y);return o;void fun1(int a,int b)float x=3;fun2(x);void fun2(float y)int x;x栈顶栈底y3fun2()fun1()运行状态及返回地址x3b2
26、a1fun1()main()运行状态及返回地址y2x1main()操作系统运行状态及返回地址此图例说明在程序执行过程中怎样通过栈此图例说明在程序执行过程中怎样通过栈“动态动态”地建立和释放局部变地建立和释放局部变量占用的内存的量占用的内存的本讲稿第二十七页,共九十页 3.5 作用域与标识符的可见性作用域与标识符的可见性3 文件作用域 2 函数声明作用域 作作用用域域:指指标标识识符符能能够够被被使使用用的的范范围围。只只有有在在作作用用域域内内标标识符才可以被访问(称为可见)。识符才可以被访问(称为可见)。本本节节重重点点讨讨论论局局部部域域和和文文件件域域(全全局局域域),其其中中局局部部域
27、域包包括括块块域域和和函函数数声声明明域域。任任何何标标识识符符作作用用域域的的起起始始点点均均为为标识符说明标识符说明处。处。下面分别介绍下面分别介绍:1 块作用域 本讲稿第二十八页,共九十页 函函数数中中定定义义的的标标识识符符,包包括括形形参参和和函函数数体体中中定定义义的的局局部变量,作用域都在该函数内,也称作部变量,作用域都在该函数内,也称作函数域函数域。1.块域块域块块指指一一对对大大括括号号括括起起来来的的程程序序段段。块块中中定定义义的的标标识识符符,作用域在块内。作用域在块内。复合语句是一个块。复合语句是一个块。函数也是一个块。函数也是一个块。复合语句中定义的标识符,复合语句
28、中定义的标识符,作用域仅在该复合语句中。作用域仅在该复合语句中。【例【例3.7】输入两数,按从大到小的顺序保存。输入两数,按从大到小的顺序保存。块的引入:块的引入:本讲稿第二十九页,共九十页1.块域块域由由VC+平台运行,结果如下:平台运行,结果如下:输入两整数:输入两整数:3 5调用前:实参调用前:实参a=3,b=5调用中调用中交换前:形参交换前:形参a=3,b=5交换后:形参交换后:形参a=5,b=3调用后:实参调用后:实参a=3,b=5 交换失败交换失败局部变量具有局部作用域使得程序在不同块中可以使用同名局部变量具有局部作用域使得程序在不同块中可以使用同名变量。这些同名变量各自在自己的作
29、用域中可见,在其它地变量。这些同名变量各自在自己的作用域中可见,在其它地方不可见。方不可见。【例【例3.8】设计函数完成两数交换,用主函数进行测试。设计函数完成两数交换,用主函数进行测试。本讲稿第三十页,共九十页1.块域块域 对于块中对于块中嵌套嵌套其它块的情况,如果嵌套块中有同名局其它块的情况,如果嵌套块中有同名局部变量,服从局部优先原则,即在内层块中部变量,服从局部优先原则,即在内层块中屏蔽屏蔽外层块中外层块中的同名变量,换句话说,内层块中局部变量的作用域为内层的同名变量,换句话说,内层块中局部变量的作用域为内层块;外层块中局部变量的作用域为外层除去包含同名变量的块;外层块中局部变量的作用
30、域为外层除去包含同名变量的内层块部分。内层块部分。如果块内定义的局部变量与全局变量同名,块内仍然局部如果块内定义的局部变量与全局变量同名,块内仍然局部变量优先,但与块作用域不同的是,在块内可以通过域运变量优先,但与块作用域不同的是,在块内可以通过域运算符算符“:”访问同名的全局变量。访问同名的全局变量。【例【例3.9】显示同名变量可见性。显示同名变量可见性。本讲稿第三十一页,共九十页2函数声明作用域函数声明作用域 函函数数声声明明不不是是定定义义函函数数,在在作作函函数数声声明明时时,其其中中的的形形参参作作用用域域只只在在声声明明中中,即即作作用用域域结结束束于于右右括括号号。正正是是由由于
31、于形形参参不不能能被被程程序序的的其其他他地地方方引引用用,所所以以通通常常只只要要声声明明形形参参个个数数和和类类型型,形形参参名名可可省省略略。本讲稿第三十二页,共九十页3 3 文件作用域文件作用域 文文件件作作用用域域也也称称全全局局作作用用域域。定定义义在在所所有有函函数数之之外外的的标标识识符符,具具有有文文件件作作用用域域,作作用用域域为为从从定定义义处处到到整整个个源源文文件件结结束。文件中定义的全局变量和函数都具有文件作用域。束。文件中定义的全局变量和函数都具有文件作用域。如如果果某某个个文文件件中中说说明明了了具具有有文文件件作作用用域域的的标标识识符符,该该文文件件又又被被
32、另另一一个个文文件件包包含含,则则该该标标识识符符的的作作用用域域延延伸伸到到新新的的文文件件中中。如如cincin和和coutcout是是在在头头文文件件iostreamiostream中中说说明明的的具具有有文文件件作作用用域域的的标标识识符符,它它们们的的作作用用域域也也延延伸伸到到嵌嵌入入iostreamiostream的的文文件件中。中。本讲稿第三十三页,共九十页存存储储类类型型(storage class)决决定定标标识识符符的的存存储储区区域域,即即编编译译系系统统在在不不同同区区域域为为不不同同存存储储类类型型的的标标识识符符分分配配空空间间。由由于于存存储储区区域域不不同同,
33、标标识识符符的的生生命命期期也也不不同同。所所谓谓生生命命期期,指指的的是是标标识识符符从从获获得得空空间间到到空空间间释释放放之之间间的的期期间间,标标识识符符只有在生存期中、并且在其自己的作用域中才能被访问。只有在生存期中、并且在其自己的作用域中才能被访问。3.6 存储类型与标识符的生命期存储类型与标识符的生命期 3.6.1 3.6.1 存储类型存储类型存储类型存储类型 3.3.2 3.3.2 生命期生命期生命期生命期 本讲稿第三十四页,共九十页自动变量为用自动变量为用auto说明的变量,通常说明的变量,通常auto缺省。局部变量都是自动变量,生缺省。局部变量都是自动变量,生命期开始于块的
34、执行,结束于块的结束,其原因是自动变量的空间分配命期开始于块的执行,结束于块的结束,其原因是自动变量的空间分配在栈中,块开始执行时系统自动分配空间,块执行结束时系统自动释放在栈中,块开始执行时系统自动分配空间,块执行结束时系统自动释放空间。故自动变量的生命期和作用域是一致的。空间。故自动变量的生命期和作用域是一致的。3.6.1 存储类型存储类型 为为提提高高程程序序运运行行效效率率,可可以以将将某某些些变变量量保保存存在在寄寄存存器器中中,即即用用register说明为寄存器变量,说明为寄存器变量,但不提倡使用但不提倡使用。C+中关于存储类型的说明符(中关于存储类型的说明符(storage c
35、lass specifier)有四个:)有四个:auto、register、static和和extern。其中用。其中用auto和和register修饰的称为自动修饰的称为自动存储类型,用存储类型,用static修饰的称为静态存储类型,用修饰的称为静态存储类型,用extern修饰的称为外修饰的称为外部存储类型。部存储类型。1 1 自动存储类型自动存储类型本讲稿第三十五页,共九十页static说说明明的的变变量量称称为为静静态态变变量量。根根据据定定义义的的位位置置不不同同,还还分分为为局局部部静静态态变变量量和和全全局局静静态态变变量量,也也称称内内部部静静态态变变量量和和外外部部静静态态变变
36、量量。静静态态变变量量均均存存储储在在全全局局数数据据区区,如如果果程程序序未未显显式式给给出出初初始始化化值值,系系统统自自动动初初始始化化为为全全0,且且初初始始化化只只进进行行一一次次;静静态态变变量量占占有有的的空空间间要要到到整整个个程程序序执执行结束才释放,故静态变量具有全局生命期。行结束才释放,故静态变量具有全局生命期。3.6.1 存储类型存储类型局局部部静静态态变变量量是是定定义义在在块块中中的的静静态态变变量量,当当块块第第一一次次被被执执行行时时,编编译译系系统统在在全全局局数数据据区区为为其其开开辟辟空空间间并并保保存存数数据据,该该空空间间一一直直到到整整个个程程序序结
37、结束束才才释释放放。局部静态变量具有局部作用域,但却具有全局生命期。局部静态变量具有局部作用域,但却具有全局生命期。2 2 2 2 静态存储类型静态存储类型静态存储类型静态存储类型【例【例3.10】自动变量与局部静态变量的区别自动变量与局部静态变量的区别本讲稿第三十六页,共九十页3.6.1 存储类型存储类型3 3 3 3 外部存储类型外部存储类型外部存储类型外部存储类型一个一个C+程序可以由多个源程序文件组成。多文件程序系统可以通过程序可以由多个源程序文件组成。多文件程序系统可以通过外外部存储类型部存储类型的变量和函数来的变量和函数来共享共享某些数据和操作。某些数据和操作。在一个程序文件中定义
38、的全局变量和函数缺省为外部的,即其作用域可在一个程序文件中定义的全局变量和函数缺省为外部的,即其作用域可以延伸到程序的其他文件中。其他文件如果要使用这个文件中定义的全以延伸到程序的其他文件中。其他文件如果要使用这个文件中定义的全局变量和函数,应该在使用前用局变量和函数,应该在使用前用“extern”作外部声明。外部声明通常作外部声明。外部声明通常放在文件的开头(放在文件的开头(函数函数总是总是省略省略extern)。)。外部变量声明不同于全局变量定义,变量定义时编译器为其分配外部变量声明不同于全局变量定义,变量定义时编译器为其分配存储空间,而变量声明则表示该全局变量已在其他地方定义过,存储空间
39、,而变量声明则表示该全局变量已在其他地方定义过,编译系统不再分配存储空间。编译系统不再分配存储空间。外部的全局变量或函数加上外部的全局变量或函数加上static修饰,就成为静态全局变量或静态修饰,就成为静态全局变量或静态函数。静态的全局变量和函数作用域限制在本文件,其他文件即使使函数。静态的全局变量和函数作用域限制在本文件,其他文件即使使用外部声明也无法使用该全局变量或函数。用外部声明也无法使用该全局变量或函数。【例【例3.11】外部存储类型的例子】外部存储类型的例子本讲稿第三十七页,共九十页3.6.2 生命期生命期1.1.静态生命期静态生命期 静态生命期静态生命期(Static extent
40、或或Static storage duration)指的是)指的是标识符从程序开始运行时就存在,具有存储空间,到程序运行标识符从程序开始运行时就存在,具有存储空间,到程序运行结束时消亡,释放存储空间。具有静态生命期的标识符存放在结束时消亡,释放存储空间。具有静态生命期的标识符存放在全局数据区,如全局变量、静态全局变量、静态局部变量。具全局数据区,如全局变量、静态全局变量、静态局部变量。具有静态生命期的标识符在未被用户初始化的情况下,系统会自有静态生命期的标识符在未被用户初始化的情况下,系统会自动将其初始化为动将其初始化为0。函数驻留在代码区,也具有静态生命期。所有具有文件作用域的函数驻留在代码
41、区,也具有静态生命期。所有具有文件作用域的标识符都具有静态生命期。标识符都具有静态生命期。本讲稿第三十八页,共九十页 3.6.2 生命期生命期2.2.局部生命期局部生命期 在函数内部或块中定义的标识符具有在函数内部或块中定义的标识符具有局部生命期局部生命期(Automatic extent或或Automatic storage duration),其生命期),其生命期开始于执行到该函数或块的标识符定义处,结束于该函数或块开始于执行到该函数或块的标识符定义处,结束于该函数或块的结束处。具有局部生命期的标识符存放在栈区。具有局部生的结束处。具有局部生命期的标识符存放在栈区。具有局部生命期的标识符如
42、果未被初始化,其内容是随机的,不可引用。命期的标识符如果未被初始化,其内容是随机的,不可引用。具有局部生命期的标识符必定具有局部作用域;但反之不具有局部生命期的标识符必定具有局部作用域;但反之不然,静态局部变量具有局部作用域,但却具有静态生命期。然,静态局部变量具有局部作用域,但却具有静态生命期。本讲稿第三十九页,共九十页3.6.2 生命期生命期具有具有动态生命期动态生命期(dynamic extent或或dynamic storage duration)的标识符存放在自由存储区,)的标识符存放在自由存储区,由特定的函数调用或运算来创建和释放,如用由特定的函数调用或运算来创建和释放,如用new
43、运算符(或调用运算符(或调用malloc()函数)为变量分配存函数)为变量分配存储空间时,变量的生命期开始,而用储空间时,变量的生命期开始,而用delete运算运算符(或调用符(或调用free()函数)释放空间或程序结束时,函数)释放空间或程序结束时,变量生命期结束。关于变量生命期结束。关于new运算符和运算符和delete运算符运算符将在第七章中介绍。将在第七章中介绍。3.3.动态生命期动态生命期本讲稿第四十页,共九十页3.7 函数的递归调用函数的递归调用 递递归归是是一一种种描描述述问问题题的的方方法法,或或称称算算法法。递递归归的的思思想想可可以以简简单单地描述为地描述为“自己调用自己自
44、己调用自己”。例如用如下方法定义阶乘:。例如用如下方法定义阶乘:可以看出是用阶乘定义阶乘,这种自己定义自己的方可以看出是用阶乘定义阶乘,这种自己定义自己的方法称为递归定义。法称为递归定义。递归的引入:递归的引入:本讲稿第四十一页,共九十页递归定义的阶乘函数:递归定义的阶乘函数:fac(int n)if(n=0|n=1)return 1;else return n*fac(n-1);只要设计主函数调用阶乘函数,即可实现计算阶乘。只要设计主函数调用阶乘函数,即可实现计算阶乘。3.7 函数的递归调用函数的递归调用【例【例3.12】求求4!运行结果:运行结果:4321126244!=24说明:说明:c
45、out”n4!=”fac(4)endl;执行时是先算函数值,然后再从左到右输出各表达式的值。执行时是先算函数值,然后再从左到右输出各表达式的值。所以有两行输出,而不是第一行插在第二行赋值号与所以有两行输出,而不是第一行插在第二行赋值号与24之间。之间。本讲稿第四十二页,共九十页3.7 函数的递归调用函数的递归调用探讨:探讨:计算是先右后左。请看下一条输出语句:计算是先右后左。请看下一条输出语句:cout”n4!=”fac(4)”n3!=”fac(3)=0&ch=9?1:0;int main()char ch;while(cin.get(ch),ch!=n)if(IsNumber(ch)cout
46、是数字字符是数字字符 endl;else cout不是数字字符不是数字字符 endl;return 0;因使用频度很高,说明为内联函数。因使用频度很高,说明为内联函数。本讲稿第五十三页,共九十页3.9 头文件与多文件结构头文件与多文件结构(选读)(选读)3.9.1 头文件头文件标准库头文件:标准库头文件:考虑标识符在其他文件中的可见性。使用头文件是很有效的方法。如:考虑标识符在其他文件中的可见性。使用头文件是很有效的方法。如:#includeusing namespace std;其中的其中的iostream是是在在标准名字空间域标准名字空间域std中定义的头文件。对应的传统方式中定义的头文件
47、。对应的传统方式的文件名为的文件名为,头文件以,头文件以“.h”为后缀。为后缀。系统定义的头文件系统定义的头文件中定义了一些常用的公用标识符和函数,用户中定义了一些常用的公用标识符和函数,用户只要将头文件包含进自己的文件,就可使头文件中定义的标识符在用只要将头文件包含进自己的文件,就可使头文件中定义的标识符在用户文件中变得可见,也就可以直接使用头文件中定义的标识符和函数。户文件中变得可见,也就可以直接使用头文件中定义的标识符和函数。本讲稿第五十四页,共九十页3.9.1 头文件头文件自定义头文件:自定义头文件:除了系统定义的头文件外,用户还可以除了系统定义的头文件外,用户还可以自定义头文件自定义
48、头文件。对于具有外部存储类型的标识符,可以在其他任何一个源对于具有外部存储类型的标识符,可以在其他任何一个源程序文件中经声明后引用,因此用户完全可以将一些具有程序文件中经声明后引用,因此用户完全可以将一些具有外部存储类型的标识符的声明放在一个头文件中。具体地外部存储类型的标识符的声明放在一个头文件中。具体地说,头文件中可以包括:用户构造的数据类型(如枚举类说,头文件中可以包括:用户构造的数据类型(如枚举类型),外部变量,外部函数、常量和内联函数等具有一定型),外部变量,外部函数、常量和内联函数等具有一定通用性或常用的量,而一般性的变量和函数定义不宜放在通用性或常用的量,而一般性的变量和函数定义
49、不宜放在头文件中。头文件中。本讲稿第五十五页,共九十页3.9.2 多文件结构多文件结构 在开发较大程序时,通常将其分解为多个源程序文件,每个在开发较大程序时,通常将其分解为多个源程序文件,每个较小的程序用一个源程序文件建立。程序经过建立、编译、连较小的程序用一个源程序文件建立。程序经过建立、编译、连接,成为一个完整的可执行程序。接,成为一个完整的可执行程序。多文件结构通过工程进行管多文件结构通过工程进行管理,在工程中建立若干用户定义的头文件理,在工程中建立若干用户定义的头文件.h和源程序文件和源程序文件.cpp。头文件中定义用户自定义的数据类型,所有的程序实现则放。头文件中定义用户自定义的数据
50、类型,所有的程序实现则放在不同的源程序文件中在不同的源程序文件中。编译时每个源程序文件单独编译,如果。编译时每个源程序文件单独编译,如果源程序文件中有编译预处理指令,则首先经过编译预处理生成临时源程序文件中有编译预处理指令,则首先经过编译预处理生成临时文件存放在内存,之后对临时文件进行编译生成目标文件文件存放在内存,之后对临时文件进行编译生成目标文件.obj,编,编译后临时文件撤销。所有的目标文件经连接器连接最终生成一个完译后临时文件撤销。所有的目标文件经连接器连接最终生成一个完整的可执行文件整的可执行文件.exe。图图3.11是一个多文件系统的开发过程。是一个多文件系统的开发过程。本讲稿第五