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

时间:2014-04-21 10:35:27

标签: c arrays malloc

我正在为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;
}

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

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

谢谢!

4 个答案:

答案 0 :(得分:1)

类型int **board;表示board 必须包含指针数组,每个指针指向每行的开头。您现有的分配省略了这一点,只需在董事会中分配*g_rtnint

分配您的电路板的规范方法,假设您必须坚持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的指针数组。

此方法的另一个问题是 alignment 。保证malloc结果与任何类型对齐;但是int可能比int *具有更严格的对齐要求。我的以下代码假定它没有;如果你想要可移植,那么你可以添加一些编译时检查(或运行它,看它是否中止!)。

所需的内存量是最后两个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个整数:

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

请注意,这比仅使用1-D数组并对偏移进行算术要复杂得多,但规定必须有两级间接才能访问该板。

这也比“规范”版本更复杂。在这个版本中,我们交易代码复杂性,以减少malloc数量。如果你的程序通常只分配一块板子或少量的板子,那么这种权衡可能不值得,而规范版本会让你减少头痛。

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

答案 1 :(得分:0)

create_default_gol()未能初始化board,因此将[]运算符应用于main(),程序将访问&#34; invaid&#34;记忆和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。从你告诉我们的内容来看,它是否应该保存字节,行/列或字段的nuber是不明确的。


另外^ 2编码&#34;魔术数字&#34;像20一样是坏习惯。


同样^ 3 create_default_gol没有指定任何参数,这些参数明确地允许任何数字而不是你可能没想到的任何数字。


总而言之,我这样编码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; 
}

答案 2 :(得分:0)

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

答案 3 :(得分:0)

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

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