(1)栈(Stack):位于函数内的局部变量(包括函数实参),由编译器负责分配释放,函数结束,栈变量失效。
(2)堆(Heap):由程序员用malloc/calloc/realloc分配,free释放。如果程序员忘记free了,则会造成内存泄露,程序结束时该片内存会由OS回收。
(3)全局区/静态区(Global Static Area): 全局变量和静态变量存放区,程序一经编译好,该区域便存在。并且在C语言中初始化的全局变量和静态变量和未初始化的放在相邻的两个区域(在C++中,由于全局变量和静态变量编译器会给这些变量自动初始化赋值,所以没有区分了)。由于全局变量一直占据内存空间且不易维护,推荐少用。程序结束时释放。
(4)C风格字符串常量存储区: 专门存放字符串常量的地方,程序结束时释放。
(5)程序代码区:存放程序二进制代码的区域。
看下面的一小段代码,试着找出其中的错误:
#include <iostream>
using namespace std;
int main()
{
char a[] = "Hello"; // 分配在栈上
a[0] = 'X';
cout << a << endl;
char *p = "World"; // 分配在字符串常量存储区的地址
p[0] = 'X';
cout << p << endl;
return 0;
}
字符数组a的容量是6个字符,其内容为"hello\0"。a的内容时可以改变的,比如a[0]=‘X’,因为其是在栈上分配的。但是指针p指向的字符串"world"分配在字符串常量存储区,内容为"world\0",常量字符串的内容时不可以修改的。从语法上来说,编译器并不觉得语句p[0]='X’有什么问题,但是在运行时则会出现"access violation"非法内存访问的问题。
以下几个函数的变化要看清楚了:
char *GetString1(void)
{
char p[] = "hello,world"; //结果:h。由于数组指针指向第一元素的地址,所以调用之后是h
return p;
}
char *GetString2(void)
{
char *p = "hello,world"; //结果:hello,world。由于p指向“hello,world”字符串常量区域地址
return p;
}