存储持续性
存储持续性分为自动存储持续性,静态存储持续性,动态存储持续性。
自动存储持续性:在函数中或者代码块中定义的变量的存储持续性是自动的。执行函数或代码块时,变量被创建,执行完之后,该变量使用的内存被释放。
静态存储持续性:在函数外定义的或者用static关键字定义的变量的存储持续性是静态的。它在整个程序运行过程中都存在。
动态存储持续性:用new分配的内存,直到用delete才会被释放。
作用域和链接性
作用域是指变量的可见范围。比如函数内定义的变量的作用域是从定义的地方开始到函数结束位置。
链接性是指变量在不同文件中的共享程度。外部链接性代表变量可以被多个文件共享,内部链接性表示变量只能有它所属的文件中使用。
自动存储持续性
在默认情况下,在函数中声明的参数和变量的存储持续性是自动的,作用域为局部,没有链接性。需要注意的是,执行到代码块时,将为变量分配内存,但其作用域的起点是其声明的位置。
下面介绍C++编译器是如何处理自动变量的:
常用的方法是留出一段内存,把它看成栈。当函数被调用时,自动变量被压入栈中,栈顶指针指向变量后面下一个可用的内存单元。函数结束后,栈顶指针重新指向以前的位置,之前的变量没有被删除,但不再被标记。它所占据的空间的值将被下一个入栈的变量覆盖。
静态持续变量
静态持续性变量的链接性有3种:外部链接性(多个文件共享),内部链接性(所属文件可用),无链接性(所属函数或代码块可用)。
int a = 3; //静态变量,外部链接性
static int b = 4; //静态变量,内部链接性
void fun()
{
static int c = 5; //静态变量,无链接性
}
外部链接性的静态变量
外部链接性的静态变量可以在一个项目的多个文件里共享。需要关键字extern。
如在file1.cpp中定义了外部链接性的静态变量a,则在file2.cpp中要用带extern的声明语句,才能使用在file1.cpp中的a。
extern int a;
并且在file2.cpp中不能有这种语句
int a;
编译不会出错,运行会发生错误。这相当于定义了两个a,而且这两个a的作用域是一样的,因此编译器不会区分。在作用域不同的时候才可以定义同名变量:
int a = 2;
void fun()
{
int a = 3; //这是自动变量,会覆盖掉全局静态变量a
}
内部链接性的静态变量
内部链接性的静态变量的作用域是所属的文件中,因此就算在别的文件中定义了同名的外部链接性的静态变量,也不会发生冲突。
file1.cpp
static int a; //内部链接性的静态变量
file2.cpp
int a; //外部链接性的静态变量
在file1中,对file2的a是不可见的,因为会被覆盖掉。
还需要注意的是const对链接性的影响:
const int a = 1; //尽管没有static关键字,但const关键字也代表该静态变量是内部链接性的
extern const int b = 1; //b是外部链接性的,使用了extern覆盖掉了const默认的内部链接性
上面的第二条语句说明常量b是外部链接性,又因为是常量,所以必须在一个且只有一个文件中初始化该常量。
无链接性的静态变量
在函数或代码块内定义并被关键字修饰的是无链接性的静态变量。它只有在执行到所属的代码块时才可用,但是离开代码块之后,它的内存单元没有被释放,始终存在,直到程序结束。而且初始化的只在第一次执行,下次在进入相应的代码块时,将不再执行初始化动作。这和自动变量有很大的区别。
int *p;
{
static int a = 1;
p = &a;
cout << a << endl;
}
cout << a << endl; //这里编译会错误,因为a未被定义
cout << *p << endl; //但静态变量a的内存没有被释放,始终存在
//所以可以通过地址来访问
动态分配内存
编译器使用三块独立的内存,一块用于静态变量,一块用于自动变量,还有一块用于动态存储。
使用new分配的内存都属于动态存储。现在主要介绍定位new运算符。
通常的new是随机分配的内存,但通过定位new运算符,程序员可以自己指定被分配的内存的地址。不能delete由定位new运算符分配的内存。
int a[4] = { 1,2,3,4 };
int *p = new(a) int[4]; //被分配给p的地址是数组a的地址
for (int i = 0; i < 4; i++) //可以通过p来访问a数组中的元素
cout << *(p + i) << endl;