栈:通常用于编译期间就能确定存储大小的变量的存储区,用于在函数作用域内创建,在离开作用域后自动销毁的变量的存储区。有种说法是默认大小1M.
堆:通常用于那些在编译期间不能确定存储大小的变量的存储区。它的存储空间是不连续的。一般由malloc(或new)函数来分配内存块,并且需要用free(或delete)来释放内存。如果程序员没有释放掉,那么就会出现内存泄露问题。
全局/静态存储区:和“栈”一样,通常是用于那些在编译期间就能确定存储大小的变量的存储区。但是它用于整个程序运行期间都可见的全局变量和静态变量。
常量存储区:通常用于编译期间能确定存储大小的常量的存储区。并且在运行期间,存储区内的常量也是全局可见的。
1 #include <iostream> 2 using namespace std; 3 4 char * get_memory1() 5 { 6 char * p = (char*)malloc(sizeof(char)*20); 7 strcpy(p,"hello world"); 8 return p; 9 } 10 11 char * get_memory2() 12 { 13 char * p = "hello world"; 14 return p; 15 } 16 17 char * get_memory3() 18 { 19 char p[] = "hello world"; 20 return p; 21 } 22 23 24 int main() 25 { 26 char *q; 27 q = get_memory1(); 28 cout<<q<<endl; 29 30 q = get_memory2(); 31 cout<<q<<endl; 32 33 q = get_memory3(); 34 cout<<q<<endl; 35 system("pause"); 36 return 0 ; 37 } 38 39
根据理论来讲,第一个和第二个函数都可以正常输出"hello world",第三个函数应该会出错的,因为p数组在函数返回地址后就释放掉了,应该不可能会正确输出,但是我在实践过程中得到的结果是:三个函数都可以正常输出(我分别用了DEV-CPP和VC++2008)。不明白第三个函数为什么不会出现问题。
解:
在get_memory1()中,
局部指针变量p 存储于栈中,malloc()创建的空间存储于堆中,p指向堆中"hello world”所在的空间地址,函数调用结束,p的值被拷贝传回主函数,p被销毁。堆中的hello world还存在,q就指向这个字符串。
在get——memory2()中,
局部指针变量p 存储于栈中,字符串“hello world”被创建在常量存储区中,函数调用结束,p的值被拷贝传回主函数,p被销毁。常量存储区中的hello world还存在,q就指向这个字符串。
在get_memory3()中,
p[]不是指针,是一个数组变量,编译器回根据右值"hello world"的长度子栈上为数组分配大小为12个字符的内存存储区,其值是"hello world"。当局部数组p[12]离开作用域后被销毁这时函数返回的拷贝指向的是一个被销毁的局部变量的地址。