提问人:Blundergat 提问时间:4/13/2023 最后编辑:Blundergat 更新时间:4/13/2023 访问量:42
内部数组挂起并体验UB的struct的创建方法
Creation method for struct with internal array hanging and experiencing UB
问:
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;
}
无法到达 print 语句,因为程序挂起并在随机时间后突然退出。
我尝试以不同的方式分配结构,例如考虑数组大小和单独初始化板。但是,仍然存在相同的 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;
我将不胜感激有关如何解决问题的一些建议。
答:
2赞
Lundin
4/13/2023
#1
在循环中分配给成员之前,您不会为其分配空间:。board
game->board[i][j]
至于,这也是错误的。A 不是二维数组,不能用作二维数组。但是,它可以用作指向指针数组中第一项的指针,以模拟 2D 数组。在这种情况下,正确的用法是: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()
然而,指针到指针的版本是幼稚的(很多坏书和坏老师都在宣扬它)。查看正确分配多维数组
有几种方法可以使用 2D 数组而不是指针到指针来实现这一点。例如,使用灵活的数组成员。不幸的是,灵活的数组成员仅支持声明的一维数组,但我们可以使用一个数组作为二维数组指针的占位符。然后永远不会实际访问它作为它被声明为的一维数组。
它以牺牲可读性为代价提供了非常高效的代码。例:
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
未初始化,但现在指向分配的 2D 数组(充满垃圾)。
我们可以通过转换为适当的指针类型来填充它(这是难以阅读的部分):
snakeEntity (*board)[game->cols] = (snakeEntity(*)[game->cols]) game->board;
现在,我们可以使用此指针来填充或以其他方式访问 2D 数组,使用 2D 数组语法:
for(size_t i=0; i<game->rows; i++)
{
for(size_t j=0; j<game->cols; j++)
{
board[i][j] = whatever;
}
}
评论
board
snakeEntity
malloc
的结果。