我怎么能让一个结构有一个未知大小的数组成员?

how can i have a struct have an unknown size array member?

我试图用 c 语言制作一种扫雷克隆,但我不知道如何创建结构的可变长度数组成员并对其进行初始化。

我的结构定义

typedef struct Cell
{
    Rectangle area;         // The area the cell covers
    bool hasMine;           // If the cell covers a mine
    bool covered;           // If the cell is currently covered
    int touching;           // How many mines the cell is touching
} Cell;

typedef struct Minefield
{
    int columns;        // The amount of columns
    int rows;           // The amount of rows
    int mines;          // The amount of mines
    Cell field[];       // An array of columns*rows Cells

} Minefield;

我如何创建雷区的新实例

Minefield NewGame(int columns, int rows, int mines)
{
    int i = 0;

    Cell cells[columns*rows];

    for (i=0; i < columns*rows; i++) {
        int x = 0;
        int y = 0;

        if (i == 0) {
            Rectangle area = (Rectangle){0, 0, cellsize, cellsize};
            cells[i] = (Cell){area, false, true, 0};
        }
        else {
            Cell previous = cells[i-1];

            x = previous.area.x + cellsize;
            y = previous.area.y + cellsize;

            Rectangle area = (Rectangle){x, y, cellsize, cellsize};
            cells[i] = (Cell){area, false, true, 0};
        }
        
    }

    Minefield field = (Minefield){columns, rows, mines, cells};
    return field;
}

我是 c 的新手,我在谷歌上搜索过一些非常相似的问题,但我无法真正理解它们或它们给出的示例。我认为你可以用 gcc 扩展来做我的错误代码试图做的(或非常相似的事情),但我希望我的代码是可移植的。我怎样才能让结构具有未知大小的数组成员?

不幸的是,C 没有像 python 这样的 built-in 动态数组。但是,如果你想使用一些动态数组,你可以自己实现或者你可以看到 link C dynamically growing array 的答案,它解释了你需要有一个默认大小的起始数组,然后您可以增加数组的大小,这取决于您的算法。导入@casablance 提供的头文件后,您可以简单地将它用于您的扫雷游戏。

是的,它叫做 flexible array member。它通常与动态分配的对象一起使用。但是,您不能按值 return Minefield。如果数组 Minefield::field 的长度为 0.

,编译器将仅复制 sizeof(Minefield) 数据,对象的大小是多少

你可以这样做:

Minefield* NewGame(int columns, int rows, int mines)
{
    Cell cells[columns*rows];
    ...
    // allocate memory for Minefield and cells array just after it
    Minefield* minefield = malloc(sizeof(*minefield) + sizeof cells);
    if (!minefield) { ... error handling ... }

    // set normal fields using compund literal
    *minefield = (Minefield){columns, rows, mines};

    // copy cells `array` to `minefield->field` array
    memcpy(minefield->field, cells, sizeof cells);

    return minefield;
}

可以通过先分配Minefield并直接写入field成员来避免memcpy

Minefield* NewGame(int columns, int rows, int mines)
{
    Minefield* minefield = malloc(sizeof(Minefield) + rows * columns * sizeof(Cell));
    if (!minefield) { ... error handling ... }
    *minefield = (Minefield){columns, rows, mines};

    Cell *cells = minefield->field;
    ...
    return minefield;
}