我一直在努力创建一个Gomoku董事会。 这是董事会的顽固分子:
typedef struct Board
{
int width;
int height;
char **board;
} Board;
这是构造函数,它返回指向Board(BoardP)的指针:
BoardP createNewBoard(int width, int high)
{
BoardP board = (BoardP) malloc(sizeof(Board));
if (board == NULL)
{
reportError(MEM_OUT);
return NULL;
}
board->height = high;
board->width = width;
board->board = (char**) malloc(high * sizeof(char*));
int i;
for (i=0; i<high; i++)
{
board->board[i] = (char*) malloc(width * sizeof(char));
}
if (board->board == NULL)
{
//SHOULD I FREE EACH LINE INDIVIDUALLY??!!??!
free(board);
reportError(MEM_OUT);
return NULL;
}
return board;
}
这是我扩大董事会的尝试:
static BoardP expandBoard(BoardP theBoard, int X, int Y)
{
int newWidth = theBoard->width;
int newHeight = theBoard->height;
if (X>theBoard->height)
{
newHeight = (newHeight+1) * 2;
}
if (Y>theBoard->width)
{
newWidth = (newWidth+1) * 2;
}
BoardP result = createNewBoard(newWidth,newHeight);
int i;
for (i=0; i<newHeight; i++)
{
result->board[i] = realloc(theBoard->board[i],newWidth);
}
freeBoard(theBoard);
return result;
}
但我一直遇到分段错误,我不知道为什么。我的基本想法是对的吗? 知道我做错了什么吗?感谢
答案 0 :(得分:2)
这里有很多可能的陷阱。确保在创建不透明的数据结构时,您可以编写辅助函数以使您的生活更轻松,然后使用这些帮助程序。
我已经将代码调整为一个带有存根驱动程序的小工作示例程序。让我分解一下:
#include <stdio.h>
#include <stdlib.h>
#DEFINE BOARD_BLANK ' '
typedef struct Board
{
int width;
int height;
char **board;
} Board;
typedef Board *BoardP;
#define MEM_OUT 109
void reportError(int msg)
{
// Stub
}
这部分只是一些样板。现在让我们创建一个在createNewBoard之外的freeBoard函数,我们将专门用于释放板:
void freeBoard(BoardP board)
{
int i;
for (i=0; i<board->height; i++) // Free each row
free(board->board[i]);
free(board->board); // Free the row pointers
free(board); // Free the structure
}
现在我们将编写一个板构造函数。请注意我已经更改了错误处理代码以减少重复并增加清晰度。这也是C:中唯一常用的goto:
BoardP createNewBoard(int width, int height)
{
BoardP board = (BoardP) malloc(sizeof(Board));
if (board == NULL)
goto err1; // Error, jump to alternative error handling exit
board->height = height;
board->width = width;
board->board = (char**) malloc(height* sizeof(char*));
if (board->board == NULL)
goto err2; // Error, jump to alternative error handling exit
int i;
for (i=0; i<height; i++)
{
// Allocate each row one at a time
board->board[i] = (char*) malloc(width * sizeof(char));
if (board == NULL)
goto err3;
for (j=0; j<height; j++)
board->board[i][j] = BOARD_BLANK; // Give all the data points an initial value
}
// Successfully allocated board -- return it.
return board;
// Error handling code
err3:
while (i-- > 0) // Start freeing rows from where we left off
free(board->board[i]);
free(board->board); // Free the allocated board->board too
err2:
free(board);
err1:
reportError(MEM_OUT);
return NULL;
}
直截了当。那里没有太大的区别,但请注意我将板上的每个点初始化为我在宏中定义的“空白”值。这是因为malloc内存可以包含其中的任何内容。现在进入expandBoard函数:
BoardP expandBoard(BoardP board, int X, int Y)
{
int newWidth = board->width;
int newHeight = board->height;
if (X > board->height) // This seems backwards. Height is usually in terms of Y
newHeight = (newHeight+1)*2; // If we're trying to ensure that the new board
// can contain X as a row index, then it should be:
// newHeight = (board->height > X) ? board->height : X;
if (Y > board->width) // Same here; width is usually in terms of X
newWidth = (newWidth+1)*2; // Likewise, should this be:
// newWidth = (board->width > Y) ? board->width : Y;
// Create a new board using the constructor we already wrote
BoardP newBoard = createNewBoard(newWidth, newHeight);
int i, j;
for (i=0; i<newHeight; i++)
for (j=0; j<board->width; j++)
newBoard->board[i][j] = board->board[i][j]; // Simply copy data from old to new
freeBoard(board); // Free the old board
return newBoard;
}
阅读评论。我采取的方法只是将旧的电路板数据复制到新电路板上。那是因为我们已经分配了一个全新的电路板。你可以通过使用memcpy而不是双重嵌套循环来加快这个过程,但无论哪种方式它都应该足够快。
您之前遇到的问题是您尝试重新分配前一个板指向的旧行,但随后您释放了该板并丢失了所有重新分配的指针。这意味着您最初发布的“expandBoard”会丢弃所有旧的电路板数据,为您留下一块全新的电路板。
一般情况下,尝试远离realloc,直到你对指针感觉更舒服,并且你已经开发出了跟踪它们的诀窍。
现在用于:
int main()
{
BoardP board = createNewBoard(50, 50);
board = expandBoard(board, 3, 2); // Make sure you assign the board pointer to
// the new expanded board!
freeBoard(board);
return 0;
}
注意评论!当您调用修改并返回指针的函数时,请确保执行赋值。否则,你仍然会指向旧的,免费的对象,这对你没有好处。
或者,您始终可以将指针传递给指向修改指针的函数的指针。
无论如何,我希望有所帮助。小心!
答案 1 :(得分:1)
看起来您遇到了分段错误,因为您将新主板的行指向旧主板的重新分配内存,然后释放旧主板。当你已经在createNewBoard
函数中为新电路板分配内存时,我不确定为什么要进行重新分配。
答案 2 :(得分:0)
首先,您需要检查每一行(当它在for循环中由malloc分配时)不会失败。您已检查board->board
,但不是每行,也是malloc
',必须检查它们是否已正确分配。否则,该板的其中一行可能为NULL,当用realloc
进行尝试时,它将收到一个空指针。