C/C++内存分区模型

        分区的目标是为了更好的管理,提高效率。就像一个公司一样会分很多的部门。

        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执行的机器指令,代码区是可共享,并且是只读的。

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值