固定块内存池分配器指针链表实现崩溃问题求助
固定块内存池分配器崩溃问题分析与修复
问题核心原因
- 链表节点存储逻辑完全错误:原代码将全局指针
p_Memory_blocks的地址存入malloc的内存块,而非用内存块的头部存储下一个空闲块的指针。这导致后续*p_Memory_blocks访问的是全局变量本身而非链表节点,直接触发非法内存访问。 - 初始化失败时的释放逻辑混乱:错误的链表遍历方式导致尝试free非法地址,进一步加剧崩溃风险。
- 块大小兼容性未考虑:若
block_size小于指针类型的字节数,无法在块内存储链表指针,必然引发越界访问。
修复方案与优化代码
关键改动说明
- 要求
block_size至少能容纳一个指针(即block_size >= sizeof(void*)),否则无法实现链表管理。 - 每个内存块的头部预留指针空间,用于存储下一个空闲块的地址;若需用户使用完整
block_size,需调整malloc总大小(需确认是否符合题目内存限制)。 - 初始化时构建正确的空闲链表:
p_Memory_blocks作为链表头,每个块的头部存下一个块的地址,最后一个块的头部设为NULL。 - 修正初始化失败时的释放逻辑,正确遍历已分配的链表节点并释放。
- 调整
MyMalloc和MyFree的逻辑,基于块内存储的指针操作链表。
修复后的完整代码
#include <stdio.h> #include <stdlib.h> // 全局指针作为空闲链表头 void* p_Memory_blocks; int MemoryInit(int num_of_blocks, int block_size) { // 检查块大小是否足够存储指针 if (block_size < sizeof(void*)) { printf("block size too small to store link pointer\n"); return 1; } void* prev_block = NULL; p_Memory_blocks = NULL; for (int i = 0; i < num_of_blocks; i++) { void* new_block = malloc(block_size); if (new_block == NULL) { printf("allocating memory failed\n"); // 释放已分配的块 void* current = p_Memory_blocks; while (current != NULL) { void* next = *(void**)current; free(current); current = next; } p_Memory_blocks = NULL; return 1; } // 将新块加入空闲链表头部 *(void**)new_block = p_Memory_blocks; p_Memory_blocks = new_block; } return 0; } void* MyMalloc() { if (p_Memory_blocks == NULL) { printf("no free memory blocks available\n"); return NULL; } // 取出链表头部的空闲块 void* allocated_block = p_Memory_blocks; p_Memory_blocks = *(void**)allocated_block; // 返回给用户的是块中跳过指针的部分(若要用户使用完整block_size,直接返回allocated_block即可) allocated_block = (char*)allocated_block + sizeof(void*); return allocated_block; } void MyFree(void* block) { if (block == NULL) { return; } // 还原到块的起始地址(对应MyMalloc的指针偏移) block = (char*)block - sizeof(void*); // 将块重新加入空闲链表头部 *(void**)block = p_Memory_blocks; p_Memory_blocks = block; } // 测试示例 int main() { if (MemoryInit(5, 32) != 0) { return 1; } void* ptr1 = MyMalloc(); void* ptr2 = MyMalloc(); printf("Allocated ptr1: %p, ptr2: %p\n", ptr1, ptr2); MyFree(ptr2); void* ptr3 = MyMalloc(); printf("Reallocated ptr3: %p (should equal ptr2)\n", ptr3); return 0; }
额外说明
- 若题目要求用户可用的每个块大小严格为
block_size,则需将malloc的大小调整为block_size + sizeof(void*),此时总内存占用为num_of_blocks * (block_size + sizeof(void*)),需确认是否符合题目"总大小为block_size*num_of_blocks"的限制。如果必须严格遵守总大小,只能从block_size中扣除指针的存储开销,用户实际可用空间为block_size - sizeof(void*)。 - 代码中使用
void*替代原有的int*,因为指针操作与具体类型无关,void*更通用且避免类型转换问题。
内容的提问来源于stack exchange,提问作者Alex Babushin
相关产品推荐
相关产品推荐

