C程序运行时的内存分布
该篇博客是自己学习的总结,如果有哪里理解的不对的地方,希望大家可以指点。
一、C内存空间分布图
二、各内存区域详解
1.代码区(.text): 该区域主要存放二进制可执行文件。
2.数据区(.data): 数据区可详细分为三块区域,分别是只读数据区、初始化数据区、未初始化数据区。
1). 只读数据区(.ordata) : 顾名思义,这个区域存放的是一些常量,包括字符串常量、const修饰的全局变量;
注意一: 字符串常量都是存储在只读数据区的。看下面一个例子,
1 #include <stdio.h> 2 3 int main(void) 4 { 5 char str[] = "I Love CHINA"; 6 7 printf("the address of array: %p\n", str); 8 printg("the address of string: %p\n", "I Love CHINA"); 9 10 str[0] = 'W'; 11 printf("%s\n", str); 12 13 return 0; 14 }
调试结构为:
the address of array: 0xbfa5052f
the address of string: 0x80485f5
W Love CHINA
看到这里可能就迷糊了,上面不是说字符串常量都存放在只读数据区吗?其实原因是这样的,当我们用字符串初始化字符数组时,是先将字符串字面量存储在只读数据区,当调用该初始化所在函数时,会将在数据区的数据拷贝一份到当前数组,当前运行的程序中就有两个''I Love CHINA'';我们改变了的其实是赋值到字符数组str所对应的在栈中的空间的值,而存放在数据区的字符串常量并没有改变。
注意二: 而const修饰的局部变量还是像普通的局部变量一样存放在栈中,只是不能显式的改变该变量。
2). 初始化数据区(.rwdata): 该区域用来存放初始化不为0的全局变量和static修饰的局部变量。
3). 未初始化数据区(.bss): 与初始化数据区类似,但是它存放的是初始化为0、未初始化的全局变量和static修饰的局部变量。这样做的目的主要是为了减少可执行二进制文件占用的存储空间,特别是在一些嵌入式设备中显得尤其重要。如下图,
1 #include <stdio.h> 2 3 int arr[2000] = {2}; 4 5 int main(void) 6 { 7 printf("hello world\n"); 8 9 return 0; 10 }
1 #include <stdio.h> 2 3 int arr[2000] = {0}; 4 5 int main(void) 6 { 7 printf("hello world\n"); 8 9 return 0; 10 }
3. 栈: 栈存放的是程序中的局部变量, 当然函数形参、返回值也都存储在栈中。栈是由系统自动管理,变量的出栈入栈操作都由系统通过移动栈顶指针来完成来完成,并不是真正的清除变量,所以当我们使用局部变量之前一定要给它赋值,否则就是一个不确定的值。
4.堆: 堆空间解决了自动分配不灵活,对内存造成浪费等问题。可以通过malloc函数申请所需大小的空间,注意这块空间申请了之后会一直存在,所以一定要和free一起使用,等用完之后马上释放,否则会造成内存泄漏,严重会导致程序停止运行。我们使用mallco函数带来方便灵活的同时,也带来了内存碎片的问题,所以当要求程序长时间运行时,必不可免的就要解决malloc带来的内存碎片问题。