4.3全局变量和局部变量4.3.1变量的存储机制与C++的内存布局4.3.2全局变量4.3.3局部变量4.3.1变量的存储机制与C++的内存布局自由存储区(动态数据)操作系统为一个C++程序的运行所分配的内存分为四个区域,如图4.3所示:栈区(函数局部数据)全局数据区(全局、静态)代码区(程序代码)(main()函数局部数据)自由存储区(动态数据)存储区域说明:(1)代码区(Codearea):存放程序代码,即程序中各个函数的代码块;(2)全局数据区(Dataarea):存放全局数据和静态数据;分配该区时内存全部清零,结果变量的所有字节等效初始化为全0。(3)栈区(Stackarea):存放局部变量,如函数中的变量等;分配栈区时不处理内存,即变量取随机值。(4)自由存储区(Freestorearea):存放与指针相关的动态数据。分配自由存储区时不处理内存。4.3.1变量的存储机制与C++的内存布局4.3.2全局变量在所有函数之外定义的变量称为全局变量。全局变量存放在全局数据区,因编译器自动将该区清为全0,如果用户在定义时不显式给出初始化值,则等效初始化为全0。全局变量可定义在程序开头,也可定义在中间位置,该全局变量在定义处之后的任何位置都是可以访问的,称为可见的。【例4.5】多个函数使用全局变量的例子。全局变量引入:4.3.2全局变量【例4.5】打印200调用func()函数func()200*2=400打印400n=100n=100*2=200【例4.5】多个函数使用全局变量的例子。intn=100;voidfunc(){n*=2;}intmain(){n*=2;coutnendl;func();coutnendl;return0;}4.3.3局部变量定义在函数内或块内的变量称为局部变量。程序中使用的绝大多数变量都是局部变量。局部变量在程序运行到它所在的块时建立在栈中,该块执行完毕局部变量占有的空间即被释放。故亦称为自动变量。局部变量在定义时可加修饰词auto,但通常省略。局部变量在定义时若未初始化,其值为随机数。局部变量引入:【例4.6】使用局部变量的例子。4.3.3局部变量打印main()中的t=4.5调用fun()函数fun()打印fun()中的t=5打印main()中的t=4.5t=4.5t=5【例4.6】使用局部变量的例子。voidfun(){autointt=5;//fun()中的局部变量,auto可省略coutfun()中的t=tendl;}intmain(){floatt=4.5;//main()函数中的局部变量coutmain()中的t=tendl;fun();coutmain()中的t=tendl;return0;}4.4函数调用机制局部变量占用的内存是在程序执行过程中“动态”地建立和释放的。这种“动态”是通过栈由系统自动管理进行的。(1)建立栈空间;(6)恢复现场:取主调函数运行状态及返回地址,释放栈空间;(7)继续主调函数后续语句。(5)释放被调函数中局部变量占用的栈空间;(4)执行被调函数函数体;(3)为被调函数中的局部变量分配空间,完成参数传递;(2)保护现场:主调函数运行状态和返回地址入栈;调用过程:4.4函数调用机制voidfun1(int,int);voidfun2(float);intmain(){intx=1;y=2;fun1(x,y);returno;}voidfun1(inta,intb){floatx=3;fun2(x);}voidfun2(floaty){intx;…}x栈顶栈底y3fun2()fun1()运行状态及返回地址x3b2a1fun1()main()运行状态及返回地址y2x1main()操作系统运行状态及返回地址此图例说明在程序执行过程中怎样通过栈“动态”地建立和释放局部变量占用的内存的4.5作用域与标识符的可见性3文件域2函数声明域作用域:指标识符能够被使用的范围。只有在作用域内标识符才可以被访问(称为可见)。本节重点讨论局部域和文件域(全局域),其中局部域包括块域和函数声明域。任何标识符作用域的起始点均为标识符说明处。下面分别介绍:1块域函数中定义的标识符,包括形参和函数体中定义的局部变量,作用域都在该函数内,也称作函数域。1.块域块指一对大括号括起来的程序段。块中定义的标识符,作用域在块内。复合语句是一个块。函数也是一个块。复合语句中定义的标识符,作用域仅在该复合语句中。【例4.7】输入两数,按从大到小的顺序保存。块的引入:1.块域【例4.7】a=3b=535a=3b=5a=5b=3【例4.7】输入两数,按从大到小的顺序保存,并输出结果。结果栈t=3intmain(){inta,b;//具有函数域cout输入两整数:endl;cinab;cout“a=a'\t'b=bendl;if(b=a){intt;//具有块域t=a;a=b;b=t;//交换a,b的值}couta=a'\t'b=bendl;return0;}上述程序若在最后一个cout语句处增加:couttendl;则编译时会提示错误,因为变量t的作用域只在if语句中,其它地方不可见。1.块域由VC++运行,结果如下:输入两整数:35调用前:实参a=3,b=5调用中…交换前:形参a=3,b=5交换后:形参a=5,b=3调用后:实参a=3,b=5交换失败局部变量具有局部作用域使得程序在不同块中可以使用同名变量。这些同名变量各自在自己的作用域中可见,在其它地方不可见。【例4.8】设计函数完成两数交换,用主函数进行测试。操作系统运行状态及返回地址main()3a5bmain()运行状态及返回地址swap()3a5b3t35【例4.8】设计函数完成两数交换,用主函数进行测试。#includeiostream.hvoidswap(int,int);intmain(){inta,b;//a,b作用域为main()cout输入两整数:endl;cinab;cout调用前:实参a=a','b=bendl;swap(a,b);//传值cout调用后:实参a=a','b=bendl;return0;}voidswap(inta,intb){//a,b作用域为swap()cout调用中…endl;cout交换前:形参a=a','b=bendl;intt;t=a;a=b;b=t;//交换swap()中的a,b的值cout交换后:形参a=a','b=bendl;}1.块域对于块中嵌套其它块的情况,如果嵌套块中有同名局部变量,服从局部优先原则,即在内层块中屏蔽外层块中的同名变量,换句话说,内层块中局部变量的作用域为内层块;外层块中局部变量的作用域为外层除去包含同名变量的内层块部分。如果块内定义的局部变量与全局变量同名,块内仍然局部变量优先,但与块作用域不同的是,在块内可以通过域运算符“::”访问同名的全局变量。【例4.9】显示同名变量可见性。全局n=100100200300内i=500内j=600内n=500+600=11001100500600100200+300=500500500200300外部i=200外部j=300【例4.9】显示同名变量可见性。intn=100;#includeiostream.hintmain(){inti=200,j=300;coutn'\t'i'\t'jendl;{//内部块inti=500,j=600,n;n=i+j;coutn'\t'i'\t'jendl;//输出局部变量ncout::nendl;//输出全局变量n}n=i+j;//修改全局变量coutn'\t'i'\t'jendl;return0;}2函数声明域函数声明不是定义函数,在作函数声明时,其中的形参作用域只在声明中,即作用域结束于右括号。正是由于形参不能被程序的其他地方引用,所以通常只要声明形参个数和类型,形参名可省略。3文件域文件域也称全局域。定义在所有函数之外的标识符作用域为从定义处到整个源文件结束,即文件域。文件中定义的全局变量和函数的作用域为文件域。如果某个文件中说明了作用域为文件域的标识符,该文件又被另一个文件包含,则该标识符的作用域延伸到新的文件中。如cin和cout是在头文件iostream中说明的具有文件作用域的标识符,它们的作用域也延伸到嵌入iostream的文件中。存储类型(storageclass)决定标识符的存储区域,即编译系统在不同区域为不同存储类型的标识符分配空间。由于存储区域不同,标识符的生命期也不同。所谓生命期,指的是标识符从获得空间到空间释放之间的期间,标识符只有在生存期中、并且在其自己的作用域中才能被访问。4.6存储类型与标识符的生命期4.6.1存储类型4.4.2生命期自动变量为用auto说明的变量,通常auto缺省。局部变量都是自动变量,生命期开始于块的执行,结束于块的结束,其原因是自动变量的空间分配在栈中,块开始执行时系统自动分配空间,块执行结束时系统自动释放空间。故自动变量的生命期和作用域是一致的。4.6.1存储类型为提高程序运行效率,可以将某些变量保存在寄存器中,即用register说明为寄存器变量,但不提倡使用。C++中关于存储类型的说明符(storageclassspecifier)有四个:auto、register、static和extern。其中用auto和register修饰的称为自动存储类型,用static修饰的称为静态存储类型,用extern修饰的称为外部存储类型。1自动存储类型static说明的变量称为静态变量。根据定义的位置不同,还分为局部静态变量和全局静态变量,也称内部静态变量和外部静态变量。静态变量均存储在全局数据区,如果程序未显式给出初始化值,则等效初始化为全0;静态变量占有的空间要到整个程序执行结束才释放,故静态变量具有整个程序执行期间的生命期。4.6.1存储类型局部静态变量是定义在块中的静态变量,编译系统在全局数据区为其开辟空间并保存数据,该空间一直到整个程序结束才释放。局部静态变量具有局部作用域,但却具有整个程序执行期间的生命期。如果显式给出初始化值,则在该块第一次执行时完成,且只进行一次。2静态存储类型【例4.10】自动变量与局部静态变量的区别4.6.1存储类型3外部存储类型一个C++程序可以由多个源程序文件组成。多文件程序系统可以通过外部存储类型的变量和函数来共享某些数据和操作。在一个程序文件中定义的全局变量和函数缺省为外部的,即其作用域可以延伸到程序的其他文件中。其他文件如果要使用这个文件中定义的全局变量和函数,应该在使用前用“extern”作外部声明。外部声明通常放在文件的开头(函数总是省略extern)。外部变量声明不同于全局变量定义,变量定义时编译器为其分配存储空间,而变量声明则表示该全局变量已在其他地方定义过,编译系统不再分配存储空间。外部的全局变量或函数加上static修饰,就成为静态全局变量或静态函数。静态的全局变量和函数作用域限制在本文件,其他文件即使使用外部声明也无法使用该全局变量或函数。【例4.11】外部存储类型的例子4.6.2生命期1.静态生命期静态生命期(Staticextent或Staticstorageduration)指的是标识符从程序开始运行时就存在,具有存储空间,到程序运行结束时消亡,释放存储空间。具有静态生命期的标识符存放在全局数据区,如全局变量、静态全局变量、静态局部变量。具有静态生命期的标识符在未被用户初始化的情况下,系统会等效将其初始化为全0。函数驻留在代码区,也具有静态生命期。所有具有文件作用域的标识符都具有静态生命期。4.6.2生命期2.局部生命期在函数内部或块中定义的标