c语言 - 分段错误(核心倾倒)[康威的生命游戏]



我正在为Conway的人生游戏开发一个C实现,我被要求使用以下标题:

#ifndef game_of_life_h
#define game_of_life_h
#include <stdio.h>
#include <stdlib.h>
// a structure containing a square board for the game and its size
typedef struct gol{
    int **board;
    size_t size;
} gol;
// dynamically creates a struct gol of size 20 and returns a pointer to it
gol* create_default_gol();
// creates dynamically a struct gol of a specified size and returns a pointer to it.
gol* create_gol(size_t size);
// destroy gol structures
void destroy_gol(gol* g);
// the board of 'g' is set to 'b'. You do not need to check if 'b' has a proper size and values
void set_pattern(gol* g, int** b);
// using rules of the game of life, the function sets next pattern to the g->board
void next_pattern(gol* g);
/* returns sum of all the neighbours of the cell g->board[i][j]. The function is an auxiliary 
function and should be used in the following function. */
int neighbour_sum(gol* g, int i, int j);
// prints the current pattern of the g-board on the screen
void print(gol* g);
#endif

我添加了评论来帮助解释每一位是什么。

gol.board是一个2级整数数组,包含x和y坐标,即board[x][y],每个坐标可以是1(有效)或0(无效)。

这都是一些背景信息,我正在尝试编写我的第一个函数create_default_gol(),它将返回一个指向gol实例的指针,带有20x20板。

然后,我尝试通过20x20板遍历每个坐标,并将其设置为0,运行此程序时,我得到了Segmentation fault (core dumped)

下面的代码是我的c文件,其中包含核心代码和main()函数:

#include "game_of_life.h"
int main()
{
    // Create a 20x20 game
    gol* g_temp = create_default_gol();
    int x,y;
    for (x = 0; x < 20; x++)
    {
        for (y = 0; y < 20; y++)
        {
            g_temp->board[x][y] = 0;
        }
    }
    free(g_temp);
}
// return a pointer to a 20x20 game of life
gol* create_default_gol()
{
    gol* g_rtn = malloc(sizeof(*g_rtn) + (sizeof(int) * 20 * 20));
    return g_rtn;
}

这是我想实现的第一个功能,能够为每个坐标生成一个20x20板,其状态为0(死)。

请随意批评我的代码,我想确定为什么我会出现分段错误,以及我是否在create_default_gol()函数中正确分配了内存。

谢谢!

类型int **board;意味着board必须包含一个指针数组,每个指针指向每行的开头。您现有的分配忽略了这一点,只分配*g_rtn加上板中的int

假设你必须坚持int **board;类型,那么分配你的董事会的典型方式是:

gol* g_rtn = malloc(sizeof *g_rtn);
g_rtn->size = size;
g_rtn->board = malloc(size * sizeof *g_rtn->board);
for (int i = 0; i < size; ++i)
    g_rtn->board[i] = malloc(size * sizeof **g_rtn->board);

这段代码涉及很多malloc小块。您可以将板上的行和列压缩为一个单独的分配,但也需要设置指向每行开头的指针,因为board必须是指向int的指针数组。

这种方法的另一个问题是对齐。保证malloc结果对任何类型都是对齐的;但是CCD_ 16可能具有比CCD_ 17更严格的对准要求。下面的代码假设它没有;如果你想移植,那么你可以添加一些编译时检查(或者运行它,看看它是否中止!)。

所需的内存量是最后两个malloc:的总和

g_rtn->board = malloc( size * size * sizeof **g_rtn->board 
    + size * sizeof *g_rtn->board );

然后第一行将在行指针结束后开始(强制转换是必要的,因为我们将int **转换为int *,使用void *意味着我们不必重复单词int):

g_rtn->board[0] = (void *) (g_rtn->board + size);

其他行中的每一行都有size int:

for (int i = 1; i < size; ++i)
    g_rtn->board[i] = g_rtn->board[i-1] + size;

请注意,这比只使用一维数组和计算偏移量要复杂得多,但它规定必须有两个间接级别才能访问板。

此外,这比"规范"版本更复杂。在这个版本中,我们用代码复杂性来换取malloc数量减少的好处。如果你的程序通常只分配一个板或少量板,那么这种权衡可能不值得,而且规范版本会让你更少头疼。

最后,可以在单个malloc中同时分配*g_rtn和板,正如您在问题中所尝试的那样。然而,我的建议(基于经验)是,将董事会分开更简单。如果棋盘是对游戏对象的单独分配,它会使代码更清晰,使对象更容易使用和更改。

create_default_gol()未能初始化board,因此对其应用[]运算符(在main()中),程序访问"invaid"内存,并使用ethis引发未定义的行为。

虽然分配了足够的内存,但代码仍然需要通过使板指向内存

gol->board = ((char*) gol) + sizeof(*gol);

更新

正如Matt McNabb所指出的,board的注释指向指向int的指针数组,因此初始化更为复杂:

gol * g_rtn = malloc(sizeof(*g_rtn) + 20 *  sizeof(*gol->board));
g_rtn->board = ((char*) gol) + sizeof(*gol);
for (size_t i = 0; i<20; ++i)
{
  g_rtn->board[i] = malloc(20 * sizeof(*g_rtn->board[i])
}

此外,该代码未设置gol的成员size。根据您告诉我们的内容,尚不清楚它是否应包含字节、行/列或字段的核心。


另外,^2编码像20这样的"幻数"是个坏习惯。


此外,^3 create_default_gol没有指定任何参数,这明确地允许任何数字m,而不是像您可能预期的那样不允许任何数字。


总而言之,我会把create_default_gol()编码成这样:

gol * create_default_gol(const size_t rows, const size_t columns)
{
  size_t size_rows = rows * sizeof(*g_rtn->board));
  size_t size_column = columns * sizeof(**g_rtn->board));
  gol * g_rtn = malloc(sizeof(*g_rtn) + size_rows);
  g_rtn->board = ((char*) gol) + sizeof(*gol);
  if (NULL ! = g_rtn)
  {
    for (size_t i = 0; i<columns; ++i)
    {
      g_rtn->board[i] = malloc(size_columns); /* TODO: Add error checking here. */
    }
    g_rtn->size = size_rows * size_columns; /* Or what ever this attribute is meant for. */
  }
  return g_rtn; 
}
gol* create_default_gol()
{
    int **a,i;
    a = (int**)malloc(20 * sizeof(int *));
    for (i = 0; i < 20; i++)
        a[i] = (int*)malloc(20 * sizeof(int));
    gol* g_rtn = (gol*)malloc(sizeof(*g_rtn));
    g_rtn->board = a;
    return g_rtn;
 }
int main()
{
// Create a 20x20 game
    gol* g_temp = create_default_gol();
    int x,y;
    for (x = 0; x < 20; x++)
    {
        for (y = 0; y < 20; y++)
        {
            g_temp->board[x][y] = 10;
        }
    }
    for(x=0;x<20;x++)
       free(g_temp->board[x]);
    free(g_temp->board);
    free(g_temp);
}
main (void)
{
    gol* gameOfLife;
    gameOfLife = create_default_gol();
    free(gameOfLife);
}
gol* create_default_gol()
{
    int size = 20;
    gol* g_rtn = malloc(sizeof *g_rtn);
    g_rtn = malloc(sizeof g_rtn);
    g_rtn->size = size;
    g_rtn->board = malloc(size * sizeof *g_rtn->board);
    int i, b;
    for (i = 0; i < size; ++i){
        g_rtn->board[i] = malloc(sizeof (int) * size);
        for(b=0;b<size;b++){
                g_rtn->board[i][b] = 0;
        }
    }
    return g_rtn;
}

或者,由于您还需要添加一个自定义大小的create_gol(size_tnew_size),因此您也可以将其编写如下。

main (void)
{
    gol* gameOfLife;
    gameOfLife = create_default_gol();
    free(gameOfLife);
}
gol* create_default_gol()
{
    size_t size = 20;
    return create_gol(size);
}
gol* create_gol(size_t new_size)
{
    gol* g_rtn = malloc(sizeof *g_rtn);
    g_rtn = malloc(sizeof g_rtn);
    g_rtn->size = new_size;
    g_rtn->board = malloc(size * sizeof *g_rtn->board);
    int i, b;
    for (i = 0; i < size; ++i){
        g_rtn->board[i] = malloc(sizeof (int) * size);
        for(b=0;b<size;b++){
                g_rtn->board[i][b] = 0;
        }
    }
    return g_rtn;
}

这样做只会最大限度地减少所需的代码量。

相关内容

  • 没有找到相关文章

最新更新