添加结构代码后,Valgrind 无效写入

Valgrind invalid write, after struct code addition

对于学校,我必须用单元格初始化地图。 在使用 Valgrind 分析我的代码时,我 运行 遇到了一些问题。 我使用的初始化函数之前工作,但在添加两个额外的整数指针和一个整数后停止运行。内存是动态分配的,错误出现在之前也存在的部分,这让我很困惑。发生的错误如下:

==4877== Invalid write of size 4
==4877==    at 0x401723: initialize_map (list.c:312)
==4877==    by 0x400B99: main (initialization.c:14)
==4877==  Address 0x550deb8 is 0 bytes after a block of size 2,584 alloc'd
==4877==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4877==    by 0x4016EA: initialize_map (list.c:306)
==4877==    by 0x400B99: main (initialization.c:14)
==4877== 
==4877== Invalid write of size 4
==4877==    at 0x40172D: initialize_map (list.c:313)
==4877==    by 0x400B99: main (initialization.c:14)
==4877==  Address 0x550debc is 4 bytes after a block of size 2,584 alloc'd
==4877==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4877==    by 0x4016EA: initialize_map (list.c:306)
==4877==    by 0x400B99: main (initialization.c:14)
==4877== 

valgrind: m_mallocfree.c:277 (mk_plain_bszB): Assertion 'bszB != 0' failed.
valgrind: This is probably caused by your program erroneously writing past the
end of a heap block and corrupting heap metadata.  If you fix any
invalid writes reported by Memcheck, this assertion failure will
probably go away.  Please try that before reporting this as a bug.

初始化代码如下:

worldmap* initialize_map(game_settings* settings)
{   
    int maxplayers = 10;
    int rows = settings->rows;
    int cols = settings->cols;
    worldmap* world = malloc(sizeof(worldmap)); //free in cleanup_map
    if(world != NULL)
    {   
        world->rows = rows;
        world->cols = cols;
        world->map = malloc(sizeof(cell)*rows*cols); //free in cleanup_map
        for(int i = 0; i < rows;i++)
        {
            for(int j = 0; j < cols;j++)
            {
            cell* cell = index_map(world, j, i); //cell* is world->map + offset
            cell->type = CELL_DIRT;
            cell->owner =  0;
            }
        }
        world->players = 0;
        world->score = NULL; //NULL pointer, since this pointer set in a later function
        world->playerturns = NULL; //NULL pointer, since this pointer set in a later function
        return world;
    }
    else{printf("No world found.\n");}
}

initialize_map() 代码的新增内容是:int maxplayersworld->playersworld->scoreworld->playerturns,其余代码在 运行 它在 valgrind 中,没有这些添加。在这段代码中 index_map() returns a cell* w->map+y_offset + x_offset

我在其他几篇文章中读到,这可能与像这样再次单独分配整数值和整数指针有关(我试图在出现无效写入错误的部分执行此操作):

world->map = malloc(sizeof(cell)*rows*cols);
for(int i = 0; i < rows;i++)
{
    for(int j = 0; j < cols;j++)
    {
       cell* cell = index_map(world, j, i); //cell8 is world->map + offset
       cell->type = malloc(sizeof(celltype);
       *(cell->type) = CELL_DIRT;
       cell->owner =  malloc(sizeof(int);
       *(cell->type) = 0;
    }
}

尝试编译这段代码时,出现以下错误:

"invalid type argument of unary ‘*’ (have ‘unsigned int’) *(cell->type) = 0;

这些是我使用的结构:

单元格结构:

typedef struct{
    celltype type;
    unsigned int owner;
} cell;

世界地图结构:

typedef struct
{
    cell* map;
    unsigned int rows; 
    unsigned int cols;
    int players;
    int* score;
    int* playerturns;
} worldmap;

单元格结构保持不变,世界地图结构之前仅由cell* mapunsigned int rowsunsigned int cols.

组成

编辑 index_map代码:

cell* index_map(worldmap* w, int x, int y)
{   
    cell* place;
    place = w->map + x*w->cols + y;
    return place;
}
  • cell->type = malloc(sizeof(celltype); 类型不是指针。你为 cell 本身分配内存吗?什么是 index_max
  • cell* cell 对类型和变量使用相同的名称并不是一个好主意。
  • *(cell->type) 是废话。使用 cell->type(*cell).type(前者更具可读性)。
  • 总的来说,您在几个似乎没有任何意义的地方使用了 malloc,您可以改用普通变量。
  • 你在哪里 free() 这一切?如果您不这样做,Valgrind 可能会变得不高兴。

以此类推

valgrind 错误基本上是说您访问的内存超出了您分配的映射范围。现在您已经包含了 index_map 函数,原因就很清楚了。

想象一下,如果您的地图是 5 列 x 2 行 - 那么大小为 10 个单元格。这意味着最多 x 和 y 可能是 4 和 1。你的函数计算 4*5+1 到 return 第 21 个单元格......计算出来的代码应该是这个

place = w->map + x*w->rows + y;

place = w->map + x + y*w->cols;

这会给你 4*2+1 或 4+1*5 = 第 9 个单元格。

至于您提到的其他问题,您不需要为这些值分配内存,因为它们不是指针。例如

cell->owner =  malloc(sizeof(int);

cell->owner 是一个无符号整数,因此您只需 cell->owner = 10; 即可为其赋值。

此外,您也不需要取消引用它们两次来使用它们 - *(cell->owner) 太过分了,只需要 cell->owner