我正在为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>
谢谢!
答案 0 :(得分:1)
类型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的指针数组。
此方法的另一个问题是 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;
}
这样做可以最大限度地减少所需的代码量。