我正在使用C语言中的连接四游戏模拟器。
https://en.wikipedia.org/wiki/Connect_Four
第一步是为游戏创建一个棋盘环境。我继续做了一个数据类型board_t,这是一个包含动态大小的数组的结构,它将保存在单维数组中播放的移动。 Board_t还包括电路板的高度和宽度信息,因此可以正确的方式检索。
我在board_create()函数中初始化这个板,并在board_can_play()函数中使用这个初始化的board_t变量来检查在给定的游戏中是否可以进行任何游戏。这是代码。
<ListView>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
...
</ListView>
但是,每当我从board_can_play()调用board_t * b时,程序会给出分段错误。更具体地说,
#include <stdlib.h>
#include <assert.h>
#define PLAYER_BLUE 2
#define PLAYER_YELLOW 1
#define PLAYER_EMPTY 0
typedef unsigned char player_t;
typedef struct board_t
{
unsigned int width;
unsigned int height;
unsigned int run;
player_t * moves;
} board_t;
bool board_create (board_t ** b, unsigned int height, unsigned int width, unsigned int run, const player_t * i)
{
//Declare a board_t variable temp_b where parameters will be saved.
board_t temp_b;
//Create a pointer and malloc a memory location based on width and height.
temp_b.moves = malloc(sizeof(unsigned char)*(height*width));
//Itereate through the moves and initialize with the given player_t
int j;
for (j = 0; j < width*height; j++)
{
temp_b.moves[j] = PLAYER_EMPTY;
}
//Input all the values to temp_b
temp_b.height = height;
temp_b.width = width;
temp_b.run = run;
//Make a temporary pointer and assign that pointer to *b.
board_t * temp_b_ptr = malloc(sizeof(board_t));
temp_b_ptr = &temp_b;
*b = temp_b_ptr;
return true;
};
/// Return true if the specified player can make a move on the
/// board
bool board_can_play (const board_t * b, player_t p)
{
unsigned int i;
unsigned int height = board_get_height(b);
unsigned int width = board_get_width(b);
for(i = (height-1)*width; i < height*width; i++)
{
if (b->moves[i] == PLAYER_EMPTY)
{
return true;
}
}
return false;
}
这一行给了我一个分段错误。此外,在main()中运行良好的函数在board_can_play()中不起作用。例如,
if (b->moves[i] == PLAYER_EMPTY)
应该得到3和3,但得到2和419678?我花了大约7个小时搞清楚,但无法弄清楚发生了什么。
答案 0 :(得分:2)
在if
语句中提供了段错误,
if (b->moves[i] == PLAYER_EMPTY)
问题不在于如何分配moves
,而是如何分配b
本身。在board_create()
中,您将在此处返回一个临时对象:
board_t * temp_b_ptr = malloc(sizeof(board_t));
temp_b_ptr = &temp_b;
*b = temp_b_ptr;
malloc
指针丢失(您正在覆盖它),只是返回(通过*b
)指向局部变量的指针。
因此,将分配移至顶部并使用temp_b_ptr
代替temp_b
:
board_t *temp_b_ptr = malloc(sizeof(board_t));
if( !temp_b_ptr ) {
/* error handling */
}
....
....
*b = temp_b_ptr;
答案 1 :(得分:1)
我会用以下方式解决你的问题。并不是说我已经存在一些错误处理,并且在完成时添加了一种破坏电路板的方法。
以下代码使用gcc-4.8.2在Ubuntu 14.01 LTS中编译时没有任何警告。我使用以下命令行编译代码:
gcc -g -std=c99 -pedantic -Wall connect4.c -o connect4
现在,转到代码。你没有提供main,所以我创建了一个快速存根主体:
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <assert.h>
#define PLAYER_BLUE 2
#define PLAYER_YELLOW 1
#define PLAYER_EMPTY 0
typedef unsigned char player_t;
typedef struct board_t
{
unsigned int width;
unsigned int height;
unsigned int run;
player_t * moves;
} board_t;
bool board_create(board_t** b, unsigned int height, unsigned int width);
void board_destroy(board_t** b);
int board_get_height(const board_t* b);
int board_get_width(const board_t* b);
int main(int argc, char** argv)
{
board_t* pBoard = NULL;
if(board_create(&pBoard, 4, 4))
{
printf("board dimensions: %d by %d\n", board_get_height(pBoard), board_get_width(pBoard));
// TODO : put game logic here...
board_destroy(&pBoard);
}
else
{
fprintf(stderr, "failed to initialize the board structure\n");
}
return 0;
}
在主要内容中看不多,就像你期望的那样。接下来是board_create
功能。请注意,我删除了run
和player_t
参数,因为我没有看到您在代码中使用它们。
bool board_create(board_t** b, unsigned int height, unsigned int width)
{
bool bRet = false;
if(*b != NULL) // we already have a board struct laying about
{
board_destroy(b);
}
if(NULL != (*b = malloc(sizeof(board_t))))
{
(*b)->width = width;
(*b)->height = height;
if(NULL != ((*b)->moves = malloc(sizeof(unsigned char*)*(height * width))))
{
for(int j = 0; j < height * width; j++)
(*b)->moves[j] = PLAYER_EMPTY;
bRet = true;
}
else
{
/* TODO : handle allocation error of moves array */
}
}
else
{
/* TODO : handle allocation error of board struct */
}
return bRet;
}
关于这个功能的几点评论;
malloc
都会检查以确保我们确实获得了我们想要的内存。我倾向于将支票放在与malloc
相同的陈述中,但这是个人偏好。true
。请注意,我只在执行两次分配后才返回true,并且它们都成功了。好的,我添加的新功能board_destroy
:
void board_destroy(board_t** b)
{
if(*b != NULL) // no board struct, nothing to do..
{
if((*b)->moves != NULL)
{
free((*b)->moves);
}
free(*b);
*b = NULL;
}
}
对此功能的一些评论;
free
该数组。 (free
- 首先是板结构意味着你丢失了对移动数组的唯一引用,然后你就会泄漏内存。)free
移动数组之前,我再次检查它是否存在。 您没有提供board_get_ *函数的实现细节,但是根据它们的用法,我怀疑您将它们实现为:
int board_get_height(const board_t* b)
{
return (b->height);
}
int board_get_width(const board_t* b)
{
return (b->width);
}
由于不确定您打算如何使用它,我没有对您的board_can_more
功能做任何事情。
快速运行上述代码:
******@ubuntu:~/junk$ ./connect4
board dimensions: 4 by 4
******@ubuntu:~/junk$
我个人认为,在进行大量内存分配时,在C或C ++中释放时,应定期在valgrind下运行程序,以确保不泄漏内存或存在其他与内存相关的错误。下面是在valgrind下运行此代码的示例:
*****@ubuntu:~/junk$ valgrind --tool=memcheck --leak-check=full ./connect4
==4265== Memcheck, a memory error detector
==4265== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==4265== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==4265== Command: ./connect4
==4265==
board dimensions: 4 by 4
==4265==
==4265== HEAP SUMMARY:
==4265== in use at exit: 0 bytes in 0 blocks
==4265== total heap usage: 2 allocs, 2 frees, 152 bytes allocated
==4265==
==4265== All heap blocks were freed -- no leaks are possible
==4265==
==4265== For counts of detected and suppressed errors, rerun with: -v
==4265== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
希望这有帮助, 吨。