将beginning赋值给memHead*变量currentPos时触发段错误求助
问题概述
实现自定义malloc时,执行memHead* currentPos = beginning;后触发段错误,测试代码仅输出前两行日志就崩溃,赋值语句后的printf从未执行。测试代码为循环调用malloc(1)和free(p)各120次。
核心错误点
初始内存块未初始化
静态数组memory未初始化,beginning直接指向该数组并当作memHead结构体使用时,其成员(如next)是随机垃圾值。后续访问currentPos->next时,会读取非法内存地址,直接触发段错误。指针运算逻辑错误
在计算新内存块地址时,直接对memHead*类型指针进行数值偏移,这会导致按memHead结构体大小而非字节数偏移,比如(memHead*) currentMemDress + sizeOfMemHead + size会偏移远大于预期的内存地址,引发非法访问。条件判断中的赋值错误
代码中else if (currentPos->next = currentPos)是赋值操作而非比较,会破坏链表结构并导致逻辑错误。初始化逻辑缺失
程序启动时未对初始内存块的元数据(sizeOfMem、free_m、next)进行初始化,导致第一次调用mymalloc时就访问未定义的结构体成员。
修复步骤
1. 初始化初始内存块
添加初始化标记,在第一次调用mymalloc时完成初始内存块的元数据设置:
static double memory[MAX_MEMORY]; void *beginning = (memHead *)(memory); static int is_initialized = 0; // 初始化标记 void *mymalloc(size_t size, char *file, int line) { printf("mymalloc called\n"); printf("Requested working bytes (reading MAX_MEMORY): %d bytes\n", MAX_MEMORY); // 第一次调用时初始化内存块头 if (!is_initialized) { memHead* initial_head = (memHead*)beginning; initial_head->sizeOfMem = MAX_MEMORY - sizeOfMemHead; // 可用数据区大小 initial_head->free_m = 1; // 标记为空闲 initial_head->next = initial_head; // 初始化为循环链表 is_initialized = 1; } memHead* currentPos = (memHead*)beginning; printf("Successfully set currentPos to beginning.\n"); // 后续分配逻辑... }
2. 修正指针运算
所有内存地址偏移需先转换为char*类型(按字节偏移),再转换回memHead*:
// 错误写法 // struct memHead* newMemoryLocation = (memHead*) currentMemDress + (int) sizeOfMemHead + size; // 正确写法 struct memHead* newMemoryLocation = (memHead*)((char*)currentMemDress + sizeOfMemHead + size);
3. 修复条件判断的赋值错误
将赋值操作改为比较操作:
// 错误写法 // else if (currentPos->next = currentPos) // 正确写法 else if (currentPos->next == currentPos)
4. 调整内存分配逻辑顺序
确保在访问结构体成员前,内存块的元数据已完成初始化,避免读取未定义值。
额外注意事项
memory数组类型改为char更合理,因为内存管理通常按字节操作,double类型会引入不必要的对齐问题。myfree中的边界检查逻辑存在错误,if (!pnt)时不应再判断pnt >= beginning + MAX_MEMORY,因为空指针永远不满足该条件,应先判断指针是否为空,再判断是否在内存池范围内。
内容的提问来源于stack exchange,提问作者Astrospherical

