c - 试图重新分配一个结构,c

标签 c struct

我一直在努力创建一个 ‫‪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;
}

但我一直遇到段错误,我不知道为什么。我的基本想法对吗? 知道我做错了什么吗?谢谢

最佳答案

这里有很多可能的陷阱。确保在创建像您这样的不透明数据结构时编写辅助函数以使您的生活更轻松,然后使用这些辅助函数。

我已经将您的代码调整为一个带有 stub 驱动程序的小型工作示例程序。让我分解一下:

#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
}

现在我们将编写一个电路板构造函数。请注意,我已经更改了错误处理代码以减少重复并增加清晰度。这也是 goto 在 C 中唯一常见的用法:

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;
}

注意评论!当您调用修改并返回指针的函数时,请确保您进行了赋值。否则,您仍然会指向旧的、自由的对象,这对您没有好处。

或者,您始终可以将指针传递给修改指针的函数。

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

关于c - 试图重新分配一个结构,c,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7082497/

相关文章:

ios - Xcode LLDB 断点条件 - 我可以在 C 函数值上中断吗?

c - 独家开卷

c++ - system() 函数找不到可执行文件的可能原因是什么?

matlab - 在没有循环的情况下访问结构中的数据

c - 使用数据结构来处理内存的个人 malloc 函数

c - 内置函数的隐式声明不兼容 ‘malloc’

c++ - 指向结构数组属性的数组指针

C 文件 IO 问题。程序未按预期运行。

c - 告诉 GCC 尾调用一个函数

C# 泛型和约束