对象的存储类型与生存期
1.对象的存储类型
存储类型决定了变量的生命期,变量生命期指从获得内存空间到释放内存空间经历的时间。
存储类型的说明符有四个:auto register static和extern
.前两者均为"自动类型",后两者分为"静态"和"外部"类型。
(1)自动存储类型
自动存储类型包括自动变量和寄存器变量两种
自动变量: 用auto说明的变量,通常省略auto。前面提到的局部变量都是自动类型,其生命期开始于块的执行,结束于块的结束。自动变量的空间分配在栈中,在程序运行过程中,块开始执行时系统自动分配空间(未初始化时值为随机数),块执行结束时系统自动释放空间。因此,自动变量的生命期和作用域是一致的。
寄存器变量: 说明时用register修饰,如
register int i;
.系统将这样说明的变量尽可能保存在寄存器中,以提高程序的运行速度。但不同的编译器对哪些变量可以说明为寄存器变量有不同的规定,而且一般的编译器都会对寄存器的使用进行优化,所以不提倡使用寄存器变量。
(2)静态存储类型
使用static关键字声明的变量称为"静态变量"。静态变量均存储在全局数据区,如果程序未显式给出初始化值,系统自动初始化为全0,且初始化只进行一次!
静态变量占有的空间要到整个程序执行结束才释放,故静态变量具有全局生命期。根据定义的位置不同,还分为"局部静态变量"和"全局静态变量",也称为"内部静态变量"和"外部静态变量"。其中,局部静态变量是定义在块中的静态变量,当块第一次被执行时,编译器在全局数据区为其开辟空间并保存数据,该控件一直到整个程序结束才释放。该变量具有局部作用域,但却具有全局生命期!
#include <iostream>
using namespace std;
int st();
int at();
int main(void)
{
int i;
for(i = 0;i<5;i++){
cout<<at()<<'\t';
}
cout<<endl;
for(i = 0;i<5;i++){
cout<<st()<<'\t';
}
cout<<endl;
return 0;
}
int st(){
static int t = 100;//局部静态变量
t++;
return t;
}
int at(){
int t = 100;
t++;
return t;
}
运行结果如下:
(3)外部存储类型
外部存储类型是用extern关键字声明的变量 。在程序文件中定义的全局变量和函数默认为外部的,其作用域可以延申到程序的其他文件中。
一个C++程序可以由多个源程序文件组成。多文件程序系统可以通过外部存储类型的变量和函数来共享某些数据和操作,方法是:
其他文件如果要使用某个文件中定义的全局变量和函数,应该在使用前用
extern
来做外部声明,表示该全局变量和函数不是在本文件中定义的。
外部声明通常放在文件的开头(函数总是省略extern)
在同一个文件中,如果函数使用到定义在该函数之后的全局变量,就必须对使用到的全局变量进行外部变量声明,以满足先定义后使用的原则。所以全局变量最好集中定义在文件的起始部分。
外部变量声明不同于全局变量定义。
变量定义时,编译器为其分配空间,而变量声明则表示该全局变量已在其他地方定义过,编译器不在分配内存空间,直接使用变量定义时所分配的空间。因此,所声明变量的变量名和类型名必须与定义时的完全相同。
2.对象的存储类型
生命期也叫生存期。生命期与存储区域相关,C++编译的程序占用的内存分为以下几个区域:
栈区: 由编译器自动分配释放,存放函数的参数值,局部变量的值等,其操作方式类似于数据结构中的栈;
堆区: 一般由程序员分配释放,若程序员不释放,程序结束时可能由操作系统回收;
全局区(静态区): 全局变量和静态变量的存储是放在一起的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域,程序结束后由系统释放;
文字常量区: 常量字符串就是放在这里的,程序结束后由系统释放该区域内存;
程序代码区: 存放函数体的二进制代码。
相应的,标识符的生命期分为:静态生命期,局部生命期和动态生命期。
(1)静态生命期
静态生命期指的是标识符从程序开始运行时存在,即具有存储空间,到程序运行结束时消亡,即释放存储空间。 具有静态生命期的标识符放在静态数据区,属于静态存储类型,如全局变量,静态全局变量,静态局部变量。
具有静态生命期的标识符在未被用户初始化的情况下,系统会自动将其初始化为全0,函数驻留在代码区,也具有静态生命期。所有具有文件作用域的标识符都具有静态生命期。
(2)局部生命期
在函数内部或者块中定义的标识符具有局部生命期,其生命期开始于执行到该函数或者块的标识符声明处,结束于该函数或块的结束处。
具有局部生命期的标识符存放在栈区。具有局部生命期的标识符如果未被初始化,其内容是随机的,不可用的。具有局部生命期的标识符必定具有局部作用域;但是静态局部变量具有局部作用域,却具有静态生命期。
(3)动态生命期
具有动态生命期的标识符由特定的函数调用或运算来创建和释放,如调用malloc()和new运算符为变量分配存储空间时,变量的生命期开始;而调用free()和delete运算符释放空间或者程序时,变量生命期结束。
具有动态生命期的变量存放在堆区。
/*不同内存存储区域示例*/
#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;
int a = 0;//全局初始化区
char *p1;//全局未初始化区
int main(void)
{
int b; //栈区
char s[] = "abc";
char *p2; //栈区
char *p3 = "123456";//"123456"在常量区,p3在栈区
static int c = 0;//全局(静态)初始化区
p1 = (char*)malloc(10);
p2 = (char*)malloc(20);//分配得来的字节区域在堆区
strcpy(p1,"123456");
cout<<p1<<endl;
return 0;
}