结构体中二维数组的释放内存

问题描述 投票:0回答:2

我正在用 C 语言编写一个小游戏,我想用 Valgrind 来测试它。 这是一个小代码示例:

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

typedef struct Game {
    int** field;
} Game;

void buildfield(Game* game, int length);
void printfield(Game* game, int length);
void freefield(Game* game, int length);

int main()
{
    struct Game* game = NULL;
    game = malloc(sizeof (struct Game));
    buildfield(game, 10);
    printfield(game, 10);
    freefield(game, 10);
    free(game);
    return 0;
}

void buildfield(Game* game, int length)
{
    game->field = (int**)malloc((sizeof (int*)) * 20);
    int i;
    for (i = 0; i < 20; i++) {
        game->field[i] = (int*) malloc((sizeof (int)) * length);
    }

    for (int line = 0; line < length; line++) {
        for (int col = 0; col < 81; col++) {
            game->field[col][line] = 0;
        }
    }
}

void printfield(Game* game, int length)
{
    for (int i = 0; i < length; i++) {
        printf("\n");
        for (int j = 0; j < 20; j++) {
            printf("%d",game->field[i][j]);
        }
    }
}

void freefield(Game* game, int length)
{
    for (int i = 0; i < length; ++i) {
        free(game->field[i]);
    }
    free(game->field);
}

Valgrind 说:

HEAP SUMMARY:
==6239==     in use at exit: 968 bytes in 22 blocks
==6239==   total heap usage: 22 allocs, 0 frees, 968 bytes allocated

我为什么不释放分配?

c malloc valgrind free
2个回答
1
投票

“为什么我不释放分配?”

如注释中所述,由于使用无法解释的值(幻数)来创建和释放内存,代码中存在额外的复杂性。由于链接中解释的原因以及其他问题,这可能会使释放计数与分配计数的匹配变得困难。由于 Valgrind 指示执行结束时剩余的内存块,因此调用每个函数的时间不匹配。

以下是您的代码和建议,包括明确对

free()
[m][c]alloc()
进行相同数量的调用的代码(我选择在此处使用
calloc()
以避免另一个循环(或
memset()
)来初始化记忆。)

另请注意,您可能需要更改此示例用于 #defines 的值以满足您的需求,但您只需在一处更改它们(在文件顶部)。

typedef struct Game {
    int** field;
} Game;

void buildfield(Game *game, int length);
void printfield(Game *game, int length);
void freefield(Game *game, int length);

#define COUNT  20//replace all magic numbers 
#define LENGTH 10//(change values of #defines to change shape and size of memory)

int main(void)//use a complete prototype for main
{
    struct Game* game = NULL;//pointer needs memory
    game = malloc(sizeof (struct Game));
    if(game)//test return of malloc before using it.
    {
        buildfield(game, LENGTH);
        printfield(game, LENGTH);
        freefield(game, LENGTH);
        free(game);
    }
    else //handle error
    {
         //do something here to handle error;//
    }
    return 0;
}

void buildfield(Game *game, int length)
{   //Note - not optimal to cast return of [c][m]alloc in C (only in C++)
    game->field = calloc(COUNT, sizeof(game->field));
    int i;
    for (i = 0; i < COUNT; i++) {
        game->field[i] = calloc(LENGTH, (sizeof (game->field[i])) );
    }
}

void printfield(Game *game,int length)
{
    for (int i = 0; i < COUNT; i++) {
        printf("\n");
        for (int j = 0; j < LENGTH; j++) {
            printf("%d",game->field[i][j]);
        }
    }
}

void freefield(Game *game,int length)
{
    for (int i = 0; i < COUNT; ++i) {
        free(game->field[i]);
    }
    free(game->field);
}

0
投票

好在函数buildfield()中 您已分配了 20 个内存块

游戏->字段 = (int **) malloc(sizeof(int *) * 20);

因此,通过 [] 操作符最多可以访问的是 game->field[19] 但在循环中,程序尝试在游戏之前访问更多块->field[19] 导致分段错误 然后程序就崩溃了。无需返回 main() ,更不用说到达 free() 语句了。所以这意味着你的程序从一开始就没有完成并且中途崩溃了。

for (int line = 0; line < length; line++)
{
    for (int col = 0; col < 81; col++)  //when col becomes 20
    {
        game->field[col][line] = 0;     //this statement will try to access the non-alloted memory block when col is 20
    }
}

要检查程序是否中途崩溃,请在与访问内存相关的语句末尾添加一些打印语句或使用调试器。因为这是运行时错误最常见的来源。

对于此代码,请尝试记住最大数量。分配的内存块可以通过特定指针访问,并更改标记的 for 循环的条件,以便它将访问分配限制内的内存。使用 malloc 函数分配的块数。

这里的问题不是 free() 不起作用。但是分段错误。 假设您提供的代码与您的代码完全相同

© www.soinside.com 2019 - 2024. All rights reserved.