变量的生存期和存储分配
1.变量的生存期
变量是内存空间的一种抽象,程序中定义的每个变量在运行时都有与之对应的内存空间。
C++把变量占有的内存空间的时间段称为生存期,分为三类:静态生存期、动态生存期、自动生存期。
- 全局变量具有静态生存期;
- 局部变量和函数的参数一般具有自动生存期;
- 对于具有动态生存期的变量,其内存空间一般用new操作分配,用delete操作收回,这样的变量称为动态变量,动态变量具有动态生存期。
定义局部变量时,可以加上存储类型修饰符:auto、static或register来显式地指出他们的生存周期。
- 局部变量的默认存储类型为auto;
- 定义static存储类型的局部变量具有静态生存期;
- 定义register存储类的局部变量也具有自动生存期,与auto存储类的局部变量的区别在于register是建议编译程序将相应的局部变量的空间分配在CPU的存储器中,目的是提高对局部变量的访问效率,当然,register类型的局部变量的存储空间也可以在CPU的寄存器中,或者内存中。
在C++程序中,定义的一个变量如果没有初始化,对于具有静态生存期的变量(全局变量、static存储类的局部变量),程序会隐式地自动把他们按位模式初始化为0;对于其他变量,编译程序不会初始化,初始值为内存空间已有的值,具有不确定性。
2.作用
- 自动的局部变量起到节省内存空间的作用,当包含auto存储类的局部变量的函数调用结束后,其中的自动局部变量的内存就被收回了。
- static存储类的局部变量的作用是,能在函数调用时获得上一次调用结束时该局部变量的值,即能在函数多次调用之间得以保留。
特别注意的是,static存储类的局部变量如果在定义中初始化,则该初始化只在函数第一次调用时进行,后面的调用中不再初始化,它的值为上一次调用结束时的值,受函数封装的保护。
3.存储的分配
当一个程序运行时,操作系统会为其分配一个内存空间,包括四个部分:静态数据区(static data)、代码区(code)、栈区(stack)和堆区(heap,或称自由存储区,free store),如下图所示(不同操作系统的顺序会不同)。
在程序的内存空间中:
- 静态数据区用于全局变量、static存储类的局部变量以及变量的内存分配;
- 代码区用于存放程序的指令,对于C++,代码区存放的是所有函数的代码;
- 栈区用于auto存储类的局部变量、函数的参数,及函数调用时的有关信息(如函数的返回地址等)的内存分配;
- 堆区用于动态变量的内存分配
静态数据区和代码区的大小是固定的,而栈区和堆区的大小将会随着程序的运行不断变化,不过,操作系统对于程序的栈区和堆区的最大值有一定的限制。
4.基于栈的函数调用的实现
函数调用是通过栈来实现的,栈是一种元素个数可变的线性数据结构。其元素的增加和减少只能在某一端进行。
- 在C++函数调用时,调用者在栈中为形参和函数返回地址分配空间,并将函数中实参的值和调用后的返回地址放入所分配的栈空间中;
- 函数调用中,被调用的函数在栈中为自动存储类的局部变量分配空间,并从栈中(通过形参)获得调用者提供的数据(实参的值);
- 函数调用后,被调用者释放局部变量的栈空间,并根据栈空间的返回地址返回到调用点(存储返回地址的栈空间将被释放);
- 调用者释放形参占用的的栈空间,然后继续执行调用之后的操作。
堆栈顺序:形参->函数返回地址->函数内的auto局部变量