使用realloc缩小内存块的C语言动态内存管理问题咨询
代码前置问题
你提供的测试代码存在一个未定义行为隐患:char *s = malloc(strlen(param)); 分配的内存长度少了1字节,strlen返回的是字符串不包含末尾\0的长度,strcpy会把字符串结束符写入超出申请范围的内存,属于缓冲区溢出,正确写法应为malloc(strlen(param) + 1)。
问题解答
问题1:你的判断完全正确。
C标准只保证realloc缩小内存后,新分配大小范围内的内存内容和原内存前对应长度的内容一致,超出范围的内存会被堆管理器标记为未分配,不属于你的合法访问范围。你删除tmp[4] = 0后还能读到完整原字符串,只是因为这块被回收的内存还没有被其他分配操作覆盖、也没有被堆管理器返回给操作系统,属于未定义行为的“正常表现”,实际运行时完全可能出现乱码、程序崩溃等情况。问题2:
free是C标准库提供的函数,内存管理是分层实现的:
C标准库的malloc/free并不会直接和操作系统交互分配每一块小内存,而是会先调用操作系统接口(比如Linux下的brk/mmap、Windows下的VirtualAlloc)申请大块连续内存,再在用户态维护内存块的分配/空闲链表,管理小块内存的分配和回收,减少频繁系统调用的开销。你调用free时,首先是标准库把对应内存块标记为空闲,加入空闲链表供后续malloc复用,只有当大块连续内存处于完全空闲状态时,标准库才会将其返还给操作系统。问题3:不需要单独释放
tmp。free操作的是指针指向的堆内存块,不是指针变量本身。s和tmp只是栈上两个存储了相同内存地址的变量,只要释放了其中任意一个指向的内存块,这块堆内存就已经被回收了。指针变量本身属于栈内存,会在函数执行结束、栈帧销毁时自动回收,不需要手动管理。
内容的提问来源于stack exchange,提问作者BartM

