内挂数组体验UB的struct创建方法

问题描述 投票:0回答:1
snakeGame * createSnakeGame()
{
    int row = 10;
    int col = 10;

    snakeGame * game = (snakeGame *) malloc(sizeof(snakeGame));

    game->rows = row;
    game->columns = col;

    for (int i = 0; i < row; i++)
    {
        if (i == 0 || i == row - 1)
        {
            for (int j = 0; j < col; j++)
            {
                game->board[i][j] = BORDER;    
            }
        }
        else
        {
            game->board[i][0] = BORDER;
            game->board[i][col - 1] = BORDER;
        }
    }

    return game;
}
typedef struct 
{
    snakeEntity ** board;
    int rows;
    int columns;
} snakeGame;
typedef enum 
{
    SNAKE_HORIZONTAL,
    SNAKE_VERTICAL,
    SNAKE_UP_RIGHT,
    SNAKE_UP_LEFT,
    SNAKE_DOWN_RIGHT,
    SNAKE_DOWN_LEFT,
    FOOD,
    BORDER,
    EMPTY
} snakeEntity;
int main()
{
    snakeGame * game = createSnakeGame();
    printf("Success");
    return 0;
}

没有到达打印语句,因为程序在随机时间后挂起并突然退出。

我尝试过以不同的方式分配结构,例如计算数组大小和单独初始化板。但是,相同的 UB 仍然存在。

// Adding the array size to the allocated memory
snakeGame * game = (snakeGame *) malloc(sizeof(snakeGame) + (row * col * sizeof(snakeEntity)));
// Allocating memory to each row individually to the size of the column
game->board = (snakeEntity **) malloc(row * sizeof(snakeEntity));
for (int i = 0; i < row; i++)
{
    game->board[i] = (snakeEntity *) malloc(col * sizeof(snakeEntity));
}
// Initialising the board separately
snakeGame * game = (snakeGame *) malloc(sizeof(snakeGame));
snakeEntity ** board = (snakeEntity **) malloc(row * col * sizeof(snakeEntity));
game->board = board;

我将不胜感激有关如何解决问题的建议。

c memory struct malloc
1个回答
0
投票

在循环中分配给

board
成员之前,您不为其分配空间:
game->board[i][j]
.

至于

snakeEntity ** board = (snakeEntity **) malloc(row * col * sizeof(snakeEntity));
,这也是错误的。
board**
不是二维数组,不能作为一个数组使用。但是,它可以用作指向指针数组中第一项的指针,以模拟二维数组。在那种情况下,正确的用法是:

game->board = malloc(row * sizeof(snakeEntity));
for(size_t i=0; i<row; i++)
{
  game->board[i] = malloc(col * sizeof(snakeEntity));
}

然后

free()
以同样的方式。


但是,指向指针版本的指针是幼稚的(很多烂书和烂老师都在宣扬它)。查看正确分配多维数组

有几种方法可以使用二维数组而不是指针到指针来实现。一个例子是使用一个灵活的数组成员。不幸的是,灵活的数组成员只支持声明的一维数组,但我们可以使用一个作为二维数组指针的占位符。然后永远不会真正访问它作为它被声明为的一维数组。

它以可读性为代价提供了非常高效的代码。例子:

typedef struct 
{
  size_t rows;
  size_t cols;
  snakeEntity board[];
} snakeGame;

然后您将一次性分配所有内容:

snakeGame* game = malloc (sizeof(snakeGame) + sizeof(snakeEntity[ROWS][COLS]));
game->rows = ROWS;
game->cols = COLS;
...
free(game); // and later free on a single line

board
未初始化但现在指向分配的二维数组(充满垃圾)。

我们可以通过转换为适当的指针类型来填充它(这是难以阅读的部分):

snakeEntity (*board)[game->cols] = (snakeEntity(*)[game->cols]) game->board;

我们现在可以使用这个指针来填充或以其他方式访问二维数组,使用二维数组语法:

for(size_t i=0; i<game->rows; i++)
{
  for(size_t j=0; j<game->cols; j++)
  {
    board[i][j] = whatever;
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.