2011-08-16 36 views
1

我一直在努力一段时间来创建一个‫‪Gomoku‬‬板。 这里的板sturct:试图重新分配一个结构体,c

typedef struct Board 
{ 
    int width; 
    int height; 
    char **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

您需要缩小到引起段错误的代码部分(理想的行)。 – hari

+0

在哪条线上得到分段错误? – sergio

+0

我怎么知道?它只说“分段错误” – yotamoo

回答

0

首先,你需要检查每一行(当它在for循环中被malloc分配)不会失败。你已经检查了board->board,但不是每一行,这也是malloc'd,必须检查它们是否被正确分配。否则,电路板的其中一行可能是NULL,当它尝试使用realloc时,它将收到一个空指针。

1

由于您将新的电路板的行指向旧电路板的重新分配的内存,因此看起来像是出现了分段错误,然后释放旧电路板。我不确定当你已经为createNewBoard函数中的新电路板分配了内存时为什么要重新分配。

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之外,我们将专门用于释放板干舷功能:

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的内存可能包含任何内容。现在扩展板功能:

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而不是双重嵌套循环来加速这个过程,但无论如何它应该足够快。

你之前遇到的问题是你试图重新分配前一个板所指向的旧行,但随后你释放了该板并丢失了所有重新分配的指针。这意味着您最初发布的“扩展板”只会丢弃所有旧板数据,而留下一块全新的板。

一般来说,尽量远离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; 
} 

注意评论!当你调用一个修改并返回一个指针的函数时,确保你做了一个任务。否则,你仍然会指向那个旧的,自由的物体,这对你没有好处。

或者,您总是可以将指针传递给指向修改指针的函数的指针。

无论如何,我希望有所帮助。保重!