分区的目标是为了更好的管理,提高效率。就像一个公司一样会分很多的部门。
C++编译器将计算机内存分为代码区和数据区,很显然,代码区就是存放程序代码,而数据区则是存放程序编译和执行过程出现的变量和常量。数据区又分为静态数据区、动态数据区以及常量区,动态数据区包括堆区和栈区。在这里分成如下区域。
1.栈区 stack
由编译器自动分配释放,存放函数的参数值、返回值和局部变量。在程序运行过程中实时分配和释放,栈区由操作系统自动管理。栈由系统自动分配,速度较快。但程序员是无法控制的。
在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
例子1:
#include<iostream>
#include<Windows.h>
using namespace std;
char* get_str()
{
char str[] = "abcdef";
return str;
}
int main()
{
char buf[128] = {0};
strcpy(buf,get_str());
printf("buf = %s\n",buf); //乱码,或者说buf指向的内存的值不确定
system("PAUSE");
return 0;
}
这个程序较小,可能多试几次最后输出的结果都是"abcdef",但是还是需要指出的是,buf指向的内容是不确定的。
例子2:
#include<iostream>
#include<Windows.h>
using namespace std;
char* get_str()
{
char str[] = "abcdef";
return str;
}
int main()
{
char* p = NULL;
p = get_str();
printf("p = %s\n",p);
system("PAUSE");
return 0;
}
运行结果截图:
总结:函数返回值要避免在栈区新创建的局部变量的地址。
2.堆区 heap
堆是由malloc/new分配的内存块,使用free/delete来释放内存,堆的申请释放工作由程序员控制,容易产生内存泄漏。
堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
例子如下:
#include<iostream>
#include<Windows.h>
using namespace std;
char* get_str()
{
char *str = (char*)malloc(100);
if(str == NULL)
{
return NULL;
}
strcpy(str,"abcdefg");
return str;
}
int main()
{
char* p = NULL;
p = get_str();
if(p != NULL)
{
printf("p = %s\n",p);
free(p); //这一句只是告诉计算机p指向的内存可以给其他变量用了
p = NULL;//这一句最好要加上,要不p还是指向原来p指向的内存的,会给程序带来隐患
}
system("PAUSE");
return 0;
}
运行结果截图如下:
这个代码和上面的栈区的代码好像,但这个程序的代码的结果却是确定的,原因就是使用了堆区的内存,用户自己申请和释放。但是需要的注意的是,在释放后要记得让那个指针赋值为NULL。
3.全局区
这个区可以划分的更加详细,包含静态区和常量区。全局变量和静态变量(用static声明的变量)是存储在一起的,把它们归一到一类----静态区,静态区的内存直到程序全部结束之后才会被释放。文字常量区(char* p = "111"后面的"111"就是文字常量),程序在运行的期间不能够被改变的。
文字常量的例子如下:
#include<iostream>
#include<Windows.h>
using namespace std;
char* get_str1()
{
char* p = "abcdef";
return p;
}
char* get_str2()
{
char* p = "abcdef";
return p;
}
int main()
{
char* p = NULL;
char* q = NULL;
//%s:指针指向内存区域的内容
//%d:打印p本身的值
p = get_str1();
printf("p = %s, p = %d\n",p,p);
q = get_str2();
printf("p = %s, p = %d",q,q);
printf("\n");
system("PAUSE");
return 0;
}
运行结果截图:
解析如下:
先运行main函数,在栈区创建变量p和q,随后运行get_str1()函数并在栈的另外一片区域创建变量p,以及在常量区(上面的那个图是在全局区)创建文字常量"abcdef\0",并把文字常量的地址返回给在main函数中的变量p,get_str1()运行完,内存释放;同样的get_str2()也是一样的过程。所以,虽然get_str1()和get_str2()是两个不相同的函数最后的返回值和指向的地址都是一样的。要是它们的文字常量不相同,那么它们的指向的地址也会不同的。
4.代码区
存放CPU执行的机器指令,代码区是可共享,并且是只读的。