作为一名程序员,要对计算机内程序内存的分配十分清楚,才能在编程中得心应手。在C/C++程序中,计算机是如何分配内存的呢?
在上面的图中,可以清楚明了的看出C/C++对内存的分配:
1.在一个C/C++程序中,程序对内存的分配分为代码区,全局区(静态区),堆区,栈区;地址是依次增大的。
2.在代码区,存放的是程序的函数体的二进制代码;
3.在代码区与全局区中间还有一个字符常量区,存放的是常量字符串,该区域中的数据具有只读属性;
4.全局区分为已初始化全局区和未初始化全局区,存放全局变量、静态数据、常量 ,程序结束后由系统释放;
5.堆区一般有程序员分配释放,地址是向上增长的;
6.栈区由编译器自动分配释放,与堆区相对而生。
下面,我通过代码验证了以上的正确性:
#include <stdio.h>
#include <stdlib.h>
int uninit;
int init = 0;
int main()
{
int s = 10;
int s2 = 20;
int s3 = 30;
int* h = (int*)malloc(sizeof(int));
int* h2 = (int*)malloc(sizeof(int));
int* h3 = (int*)malloc(sizeof(int));
char* str = "hello";
printf("code:%p\n", main);
printf("str:%p\n", str);
printf("init:%p\n", &init);
printf("uninit:%p\n", &uninit);
printf("heap1:%p\n", h);
printf("heap2:%p\n", h2);
printf("heap3:%p\n", h3);
printf("stack1:%p\n", &s);
printf("stack2:%p\n", &s2);
printf("stack3:%p\n", &s3);
return;
}
发现,从代码区向上一直到栈区,地址确实是逐渐递增的,并且堆区和栈区相向而生。
另外,我们知道,数组是一组连续的空间,那么它的地址会有怎样的规律呢?(创建一个数组,打印每个元素的地址)
int main()
{
int a[10] = {0};
int i = 0;
for(;i < 10; i++)
{
printf("%d:%p\n", i, &a[i]);
}
return;
}
问:随着下标的增大,地址也是随之增大的。那么创建在栈空间上的元素为什么地址不是逐渐减小呢?
答:因为数组是一种类型,计算机在栈空间上开辟空间时,是整体开辟的;而不是一个一个的开辟。数组开辟成功后,取最低的地址(也就是首元素的地址)作为整个数组的地址。
问:在C的程序空间分配中,程序员能使用的有哪些呢?
答:代码区,文字常量区,全局区都不由程序员申请和释放,全局区在编译时就确定好了。整个程序中程序员能使用的只有堆区和栈区,其中栈区随着函数的调用,自动申请,自动释放;而堆区的空间需要程序员主动申请和释放,如果未能进行释放,可能会造成内存泄漏。内存泄漏随着程序的结束而消失。