C语言动态数组内存释放原理及相关异常、分配规则问询
关于C语言堆内存管理的三个问题
先看示例代码:
#include <stdio.h> #include <stdlib.h> int main(){ int * ptr = (int*)malloc(sizeof(int)*100); // Allocated space for 100 integers // Some code free(ptr); // Calling free with ptr as argument return 0; }
问题1:为何调用free(ptr)能释放本案例中的全部400字节?ptr仅存储内存中一个字节的地址,且未传入数组大小参数,它是如何释放所有字节的?
malloc在分配内存时,会在返回给你的指针指向的内存区域前方(或是内部关联的管理区域)额外存储这块内存的元数据,其中就包含分配的总大小。你拿到的ptr其实是跳过了管理元数据的用户数据区起始地址,当调用free(ptr)时,系统会通过ptr反向找到对应的元数据块,从中读取内存总大小,然后把整个内存块标记为空闲,完成释放。所以不需要你手动传大小,系统自己已经记录好了。
问题2:若执行以下操作会发生什么?
ptr++; free(ptr);
这属于C语言标准里的未定义行为。free函数要求传入的指针必须是malloc、calloc或realloc返回的原始指针,或者是NULL。当你执行ptr++后,指针指向的已经不是原分配块的起始地址,free找不到对应的管理元数据,可能直接触发程序崩溃,也可能破坏堆的内存管理结构,导致后续内存操作出现莫名错误(比如内存泄漏、数据损坏、随机崩溃),具体结果完全不可预测,绝对不能这么写。
问题3:既然无法通过指针获取堆上数组的大小,为何malloc()不会在之前数组的中间位置分配新的堆内存?
堆内存的管理是基于内存块的,每个通过malloc分配出去的内存块都会被标记为“已占用”状态。malloc分配新内存时,只会在未被标记为占用的连续空闲块中寻找合适空间。之前的数组是一个完整的已占用块,整个块都处于被占用状态,所以malloc不会拆分已占用的块来分配新内存——除非你用realloc主动调整这块内存的大小,否则已占用块会保持完整,不会被中间插入新的分配。
内容的提问来源于stack exchange,提问作者Adi bhai
相关产品推荐
相关产品推荐

