You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

固定块内存池分配器指针链表实现崩溃问题求助

固定块内存池分配器崩溃问题分析与修复

问题核心原因

  • 链表节点存储逻辑完全错误:原代码将全局指针p_Memory_blocks的地址存入malloc的内存块,而非用内存块的头部存储下一个空闲块的指针。这导致后续*p_Memory_blocks访问的是全局变量本身而非链表节点,直接触发非法内存访问。
  • 初始化失败时的释放逻辑混乱:错误的链表遍历方式导致尝试free非法地址,进一步加剧崩溃风险。
  • 块大小兼容性未考虑:若block_size小于指针类型的字节数,无法在块内存储链表指针,必然引发越界访问。

修复方案与优化代码

关键改动说明

  1. 要求block_size至少能容纳一个指针(即block_size >= sizeof(void*)),否则无法实现链表管理。
  2. 每个内存块的头部预留指针空间,用于存储下一个空闲块的地址;若需用户使用完整block_size,需调整malloc总大小(需确认是否符合题目内存限制)。
  3. 初始化时构建正确的空闲链表:p_Memory_blocks作为链表头,每个块的头部存下一个块的地址,最后一个块的头部设为NULL。
  4. 修正初始化失败时的释放逻辑,正确遍历已分配的链表节点并释放。
  5. 调整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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 02:25:24