C语言实现自定义malloc()时链表遍历进入死循环问题排查
问题原因与修复方案
核心错误点
- 元数据存储在栈空间导致野指针
你在mymalloc中定义的meta_data block_meta是函数局部变量,分配在栈内存上。函数执行结束后,这块栈空间会被系统自动回收,后续函数调用会直接覆盖这块空间的内容。你将全局指针global_base指向这个局部变量的地址,相当于存储了一个野指针,多次调用mymalloc后栈空间被反复覆盖,next指针最终指向自身,就会出现无限循环、所有节点值都为最后一次赋值的4的问题。 - 元数据没有写入分配的堆内存
你的设计思路是元数据放在分配块的正前方,但你申请的size + block_size的堆内存(sbrk返回的空间)完全没有被用来存元数据,所有元数据都存在了马上要被回收的栈上,和分配的堆块完全没有关联。 - 链表插入逻辑错误
你当前写的逻辑是头插法(新节点插在链表头部),就算前面问题修复,输出顺序也会是4 -> 8 -> 10,和你预期的尾插结果相反。 - 缺失常量定义
代码里的block_size没有定义,按照你的设计应该等于sizeof(meta_data)。
关于.和->运算符的疑问
你这里的使用没有问题:.用于访问普通结构体变量的成员,->用于访问结构体指针指向的对象的成员。你之前定义的block_meta是普通栈上结构体变量,所以用.是正确的,不是问题诱因。
修复后的代码示例
#include <stdio.h> #include <unistd.h> typedef struct meta_data { size_t size; int free; struct meta_data* next; } meta_data; #define BLOCK_SIZE sizeof(meta_data) meta_data* global_base = NULL; void *mymalloc(size_t size) { if(size <= 0) { return NULL; } // 直接在sbrk申请的空间上存元数据 void* request_addr = sbrk(size + BLOCK_SIZE); if(request_addr == (void*) -1) // sbrk申请失败判断 { return NULL; } meta_data* block_meta = (meta_data*) request_addr; block_meta->size = size; block_meta->next = NULL; block_meta->free = 0; if(!global_base) // 首次分配 { global_base = block_meta; } else { // 尾插逻辑:遍历到链表末尾 meta_data* curr = global_base; while(curr->next != NULL) { curr = curr->next; } curr->next = block_meta; } // 返回元数据之后的用户可用空间地址 return (void*)((char*)block_meta + BLOCK_SIZE); } void printList() { meta_data * node = global_base; while (node != NULL) { printf("%zu", node->size); if(node->next != NULL) { printf(" -> "); } node = node->next; } printf(" \n "); } int main() { mymalloc(10); mymalloc(8); mymalloc(4); printList(); return 0; }
修复后运行输出就会和你预期的一致:10 -> 8 -> 4。
内容的提问来源于stack exchange,提问作者Umar Sheikh Salem
相关产品推荐
相关产品推荐

