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

结构体中整数数组无法释放的问题排查求助

树形结构内存释放错误排查与解决

问题场景

实现最多包含9个子节点的树形结构,将已初始化子节点的索引存入与子节点数量匹配的整数数组,释放该数组时触发堆内存错误。可编译的代码片段如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct moveNode
{
    int rating;
    // char player;
    int numPossibleMoves, *possibleMoves;
    struct moveNode **children;
};

struct moveNode *moveTreeHead;
struct moveNode *createHeadNode(void);
void initializeNode(struct moveNode *node, char *boardState);

int main()
{
    moveTreeHead = createHeadNode();

    printf("moveTreeHead->possibleMoves[1] %d\n", moveTreeHead->possibleMoves[1]);
    free(moveTreeHead->possibleMoves);
}

void initializeNode(struct moveNode *node, char *boardState)
{
    int i, possibleMovesCounter = -1;
    node->numPossibleMoves = 0;
    for (i = 0; i < 9; i++)
    {
        if (boardState[i] != 'x' && boardState[i] != 'o')
        {
            node->numPossibleMoves++;
        }
    }

    if (node->numPossibleMoves != 0)
    {
        node->possibleMoves = (int *)malloc(sizeof *(node->possibleMoves));
        for (i = 0; i < 9; i++)
        {
            if (boardState[i] != 'x' && boardState[i] != 'o')
            {
                possibleMovesCounter++;
                node->possibleMoves[possibleMovesCounter] = i;
                node->children[i] = (struct moveNode *)malloc(sizeof *(node->children[i]));
                node->children[i]->numPossibleMoves = 0;
            }
        }
    }
    else
    {
        node->possibleMoves = NULL;
    }
}

struct moveNode *createHeadNode()
{
    struct moveNode *ret = (struct moveNode *)malloc(sizeof(struct moveNode));
    ret->children = (struct moveNode **)malloc(sizeof *(ret->children) * 9);
    initializeNode(ret, "012345678");
    return ret;
}

错误信息

运行时触发堆内存检测错误:

warning: HEAP[helloworld.exe]:
warning: Heap block at 0000028AA9C23530 modified at 0000028AA9C23544 past requested size of 4

Thread 1 received signal SIGTRAP, Trace/breakpoint trap.
0x00007ffa1046a773 in ntdll!RtlRegisterSecureMemoryCacheCallback () from C:\WINDOWS\SYSTEM32\ntdll.dll

错误原因分析

错误提示核心是堆内存块被修改超出了申请的大小,问题出在initializeNode函数中:

  • 传入的boardState为"012345678"时,所有字符都不是x或o,因此node->numPossibleMoves被计算为9。
  • 但分配possibleMoves数组时,仅执行malloc(sizeof *(node->possibleMoves)),也就是只分配了1个int的内存(通常为4字节)。
  • 后续循环中给possibleMoves[0]到possibleMoves[8]赋值,会越界写入堆内存中不属于该数组的区域,破坏堆结构,最终在free时触发检测错误。

修复方案

修改possibleMoves的内存分配代码,根据numPossibleMoves的实际值分配对应大小的内存:
将原来的:

node->possibleMoves = (int *)malloc(sizeof *(node->possibleMoves));

替换为:

node->possibleMoves = (int *)malloc(sizeof(int) * node->numPossibleMoves);

修复后的完整代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct moveNode
{
    int rating;
    // char player;
    int numPossibleMoves, *possibleMoves;
    struct moveNode **children;
};

struct moveNode *moveTreeHead;
struct moveNode *createHeadNode(void);
void initializeNode(struct moveNode *node, char *boardState);

int main()
{
    moveTreeHead = createHeadNode();

    printf("moveTreeHead->possibleMoves[1] %d\n", moveTreeHead->possibleMoves[1]);
    free(moveTreeHead->possibleMoves);
    // 补充释放children节点和根节点,避免内存泄漏
    for (int i = 0; i < 9; i++) {
        free(moveTreeHead->children[i]);
    }
    free(moveTreeHead->children);
    free(moveTreeHead);
}

void initializeNode(struct moveNode *node, char *boardState)
{
    int i, possibleMovesCounter = -1;
    node->numPossibleMoves = 0;
    for (i = 0; i < 9; i++)
    {
        if (boardState[i] != 'x' && boardState[i] != 'o')
        {
            node->numPossibleMoves++;
        }
    }

    if (node->numPossibleMoves != 0)
    {
        node->possibleMoves = (int *)malloc(sizeof(int) * node->numPossibleMoves);
        for (i = 0; i < 9; i++)
        {
            if (boardState[i] != 'x' && boardState[i] != 'o')
            {
                possibleMovesCounter++;
                node->possibleMoves[possibleMovesCounter] = i;
                node->children[i] = (struct moveNode *)malloc(sizeof *(node->children[i]));
                node->children[i]->numPossibleMoves = 0;
            }
        }
    }
    else
    {
        node->possibleMoves = NULL;
    }
}

struct moveNode *createHeadNode()
{
    struct moveNode *ret = (struct moveNode *)malloc(sizeof(struct moveNode));
    ret->children = (struct moveNode **)malloc(sizeof *(ret->children) * 9);
    initializeNode(ret, "012345678");
    return ret;
}

内容的提问来源于stack exchange,提问作者mkdrive2

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 16:15:50