C程序的存储区及堆与栈区别

本文详细介绍了C程序的存储结构,包括正文段、初始化数据段、未初始化数据段、堆和栈等内容。同时对比了堆和栈的区别及其各自的特点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文主要介绍两点
1:C程序的存储区
2:堆和栈之间的区别及特点

1:C程序的存储结构


《UNIX高级编程》7.6节介绍了C程序存储区,如下图所示:
这里写图片描述

它分为:(从低地址向高地址依次排列)

1.正文段(text)
2.初始化数据段(data)
3.非初始化数据段(bss)
4.堆(heap)(由图中可以看出,堆是由低地址向高地址生长的)
5.栈(stack)(由图中可以看出,栈是由高地址向低地址生长的)
6.命令行参数和环境变量(command-line arguments and environment variables)

下面对此一一做出介绍:
正文段:也就是.text段。

CPU 执行的机器指令。

父进程和子进程之间可共享正文段。

存在于程序镜像文件中且只读, 由 exec 函数从程序镜像文件中读入内存, 例如在 shell 中正在执行的程序运行正文段的指令。

已初始化的数据:即.data段。

具有明确初始值的全局变量和静态变量

存在于程序镜像文件中,由 exec 函数从程序镜像文件中读入内存

未初始化数据段:即.bss段。

Block Started by Symbol, 即以符号开始的内存块

未初始化的数据可能是全局变量, 静态变量

bss段并不占用可执行程序的镜像的空间,而是在执行时分配内存,并由 exec 函数初始化为0, 例如声明全局数组 int a[100],不会将100个0记录在可执行文件镜像中,而只是记录了标识符a和其所占用的内存大小

变量的大小记录在符号表中,要分配的整个 bss段的大小记录在段表(Section headers)中。

对于全局变量而言,如果已经初始化了,则存放在初始化数据区中,否则就在未初始化数据段中。

堆和栈见下文介绍。

堆与栈之间有界限,其实在堆与栈之间还有一个区域,即共享库区域,比如平时用到的C库函数之类的就在这一个区域中。

命令行参数和环境变量

使程序了解进程环境,在执行时分配内存

在 shell 中执行某个程序(shell 的子进程)时,shell 进程调用 exec函数将命令行参数传递给要执行的程序

2:堆和栈

栈是由编译器自动分配并释放的,而堆是由程序员手动分配和释放的。
首先看以下代码:

int a = 0;                         //全局初始化区
char *p1;                          //全局未初始化区
main()
{
int b;                       //栈
char s[] = "abc";           //栈
char *p2;                   //栈
char *p3 = "123456";       //123456\0在常量区,p3在栈上。
static int c = 0//全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);  //分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456");     //123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一块。
}

2.1 堆和栈的特点

栈是操作系统提供的功能,特点是快速高效,缺点是对支持的数据有限制,一般是整数,指针,浮点数等系统直接支持的数据类型,并不直接支持其他的数据结构。而堆是函数库提供的功能,特点是灵活方便,数据适应面广泛,但是效率有一定降低。

栈是系统数据结构,对于进程/线程是唯一的;堆是函数库内部数据结构,不一定唯一。不同堆分配的内存无法互相操作。

栈支持静态分配和动态分配两种,静态分配和释放由编译器完成,栈的动态分配无需释放,但栈的动态分配是不被鼓励的。堆的分配和释放都是动态的。

2.2 堆和栈的空间申请

栈空间是由编译器自动分配和释放的。

堆空间是用new运算符或malloc函数申请,对应的释放函数是delete运算符和free函数。

2.3 堆和栈申请内存后的系统响应

栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出,栈不够用的情况一般是程序中分配了大量数组和递归函数层次太深。

堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。

2.4 堆和栈空间申请大小的限制

栈:是向低地址扩展的数据结构,是一块连续的内存的区域。空间大小是固定的。

堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

本文主要参考整理自:
http://blog.youkuaiyun.com/fanlu319/article/details/7769103

http://blog.youkuaiyun.com/why19911024/article/details/53033426

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值