我目前正在C中写一个象棋游戏作为我学习的项目。我用valgrind检查了内存泄漏,发现了一些泄漏。 我检查了valgrind测试的日志,发现在每个泄漏中总会有相同的函数链导致相同的点,我试图调试并跟踪漏洞,但不幸的是没有成功。
有谁可以请看下面的功能,并指出可能是什么问题? 谢谢。
编辑:我在 getAllMoves 中发现了泄漏 谢谢大家。
以下是源代码:
//THESE ARE THE STRUCTS//
typedef struct position {
char x;
int y;
struct position * next;
}position;
typedef struct move {
position* current_pos;
char* promotion;
struct move * next;
}move;
typedef struct {
move* head;
move* tail;
}moves;
//END OF STRUCTS//
/*
* Freeing a list of positions
*/
void freePositions(position* pos){
if (pos != NULL){
freePositions(pos->next);
free(pos);
}
}
/*
* Freeing a list of moves
*/
void freeMoves(move* move){
if (move != NULL){
freePositions(move->current_pos);
freeMoves(move->next);
if (move->promotion != NULL){
free(move->promotion);
}
free(move);
}
}
/* Checking if there was a check performed by "playing_color" player */
int isCheck(char playing_color , char curr_board[BOARD_SIZE][BOARD_SIZE]){
moves* player_moves = getAllMoves(playing_color, curr_board);
move * head = player_moves->head;
while (head != NULL) {
int x = head->current_pos->next->x - 97;
int y = head->current_pos->next->y - 1;
if ((curr_board[y][x] == WHITE_K && playing_color == 'B') || (curr_board[y][x] == BLACK_K && playing_color == 'W')) {
freeMoves(player_moves->head);
free(player_moves);
return 1;
}
head = head->next;
}
freeMoves(player_moves->head);
free(player_moves);
return 0;
}
/*
* Concating a move to a list of moves
*/
moves* concatMoves(moves* moves_1, move* move2){
if (move2==NULL || move2->current_pos == NULL){
return moves_1;
}
if (moves_1->tail == NULL){
moves_1->head = move2;
moves_1->tail = move2;
move2 = move2->next;
}
if (move2 != NULL){
moves_1->tail->next = move2;
moves_1->tail = move2;
move* next_move = move2;
while (next_move->next != NULL) {
next_move = next_move->next;
moves_1->tail = next_move;
}
}
return moves_1;
}
/*
* create a move from (x,y) to (x+ x_offset, y+ y_offset)
*/
move* CreateMove(position * current_pos, int x_offset , int y_offset) {
position * start_pos = calloc(1, sizeof(position));
validate(start_pos, "CreateMove");
position * new_pos = calloc(1,sizeof(position));
validate(new_pos, "CreateMove");
initPosition(new_pos, current_pos->x+x_offset, current_pos->y+y_offset);
initPosition(start_pos, current_pos->x , current_pos->y );
move *new_move = calloc(1,sizeof(move));
validate(new_move, "CreateMove");
initMove(new_move);
new_move->current_pos = start_pos;
new_move->current_pos->next = new_pos;
return new_move;
}
/*
* get all possible bishop moves from the current position
*/
moves* getBishopMoves(char playing_color, char curr_board[BOARD_SIZE][BOARD_SIZE], position* current_pos){
//flags that symbolizes we cannot move longer on the corresponding diagonal
int moved_topRight_diag = 0; int moved_topLeft_diag = 0;
int moved_downRight_diag = 0; int moved_downLeft_diag = 0;
moves * bishop_moves = calloc(1, sizeof(moves));
validate(bishop_moves, "getBishopMoves");
for (int i = 1; i < BOARD_SIZE; i++) {
if (moved_downLeft_diag && moved_topLeft_diag && moved_downRight_diag && moved_topRight_diag){
break;
}
position next_pos = { current_pos->x + i, current_pos->y + i, NULL };
move* new_move;
//check if there is a legal move from (x,y) to (x+i,y+i)
if (!moved_topRight_diag && isValidPosition(next_pos)){
if (IsEmpty(next_pos.x-97, next_pos.y-1, curr_board)){
new_move = CreateMove(current_pos, i, i);
concatMoves(bishop_moves, new_move);
}
else if (!isSameColor(playing_color, &next_pos, curr_board) && !IsEmpty(next_pos.x-97, next_pos.y-1, curr_board)){
new_move = CreateMove(current_pos, i, i);
concatMoves(bishop_moves, new_move);
moved_topRight_diag = 1;
}
else {
moved_topRight_diag = 1;
}
}
//check if there is a legal non-capture move from (x,y) to (x+i,y-i)
position next_pos1 = { current_pos->x + i, current_pos->y - i, NULL };
if (!moved_downRight_diag && isValidPosition(next_pos1)){
if (IsEmpty(next_pos1.x-97, next_pos1.y-1, curr_board)){
new_move = CreateMove(current_pos, i, -i);
concatMoves(bishop_moves, new_move);
}
else if (!isSameColor(playing_color, &next_pos1, curr_board) && !IsEmpty(next_pos1.x-97, next_pos1.y-1, curr_board)){
new_move = CreateMove(current_pos, i, -i);
concatMoves(bishop_moves, new_move);
moved_downRight_diag = 1;
}
else {
moved_downRight_diag = 1;
}
}
//check if there is a legal non-capture move from (x,y) to (x-i,y-i)
position next_pos2 = { current_pos->x - i, current_pos->y - i, NULL };
if (!moved_downLeft_diag && isValidPosition(next_pos2)){
if (IsEmpty(next_pos2.x-97, next_pos2.y-1, curr_board)){
new_move = CreateMove(current_pos, -i, -i);
concatMoves(bishop_moves, new_move);
}
else if (!isSameColor(playing_color, &next_pos2, curr_board) && !IsEmpty(next_pos2.x-97, next_pos2.y-1, curr_board)){
new_move = CreateMove(current_pos, -i, -i);
concatMoves(bishop_moves, new_move);
moved_downLeft_diag = 1;
}
else {
moved_downLeft_diag = 1;
}
}
//check if there is a legal non-capture move from (x,y) to (x-i,y+i)
position next_pos3 = { current_pos->x - i, current_pos->y + i, NULL };
if (!moved_topLeft_diag && isValidPosition(next_pos3)){
if (IsEmpty(next_pos3.x-97, next_pos3.y-1, curr_board)){
new_move = CreateMove(current_pos, -i, i);
concatMoves(bishop_moves, new_move);
}
else if (!isSameColor(playing_color, &next_pos3, curr_board) && !IsEmpty(next_pos3.x-97, next_pos3.y-1, curr_board)){
new_move = CreateMove(current_pos, -i, i);
concatMoves(bishop_moves, new_move);
moved_topLeft_diag = 1;
}
else {
moved_topLeft_diag = 1;
}
}
}
return bishop_moves;
}
/*
* get all possible queen moves from the current position , queen moves simply combine rook and bishop moves from a current position.
*/
moves * getQueenMoves(char playing_color, char curr_board[BOARD_SIZE][BOARD_SIZE], position* current_pos){
moves * queen_moves = getBishopMoves(playing_color, curr_board, current_pos);
moves* rook_moves = getRookMoves(playing_color, curr_board, current_pos);
move* rooks_move_head = rook_moves->head;
concatMoves(queen_moves, rooks_move_head);
free(rook_moves);
return queen_moves;
}
/*
* removing moves that end up with check the the playing color king
*/
void removeBadMoves(moves* all_moves, char playing_color, char curr_board[BOARD_SIZE][BOARD_SIZE]){
move* curr_move = all_moves->head;
while (curr_move != NULL){
char temp_board[BOARD_SIZE][BOARD_SIZE];
boardCopy(curr_board, temp_board);
actualBoardUpdate(curr_move, temp_board, playing_color);
if (curr_move == all_moves->head && isCheck(OppositeColor(playing_color), temp_board)) {
all_moves->head = all_moves->head->next;
freePositions(curr_move->current_pos);
free(curr_move);
curr_move = all_moves->head;
continue;
}
else if (curr_move->next != NULL) {
boardCopy(curr_board, temp_board);
actualBoardUpdate(curr_move->next, temp_board, playing_color);
if (isCheck(OppositeColor(playing_color), temp_board)){
move* temp_move = curr_move->next;
curr_move->next = curr_move->next->next;
if (temp_move == all_moves->tail){
all_moves->tail = curr_move;
}
freePositions(temp_move->current_pos);
free(temp_move);
continue;
}
}
curr_move = curr_move->next;
}
}
/*
* get all possible moves from a given positiion at the board
*/
moves* getMovesFromPosition(char playing_color, char curr_board[BOARD_SIZE][BOARD_SIZE], position* current_pos){
char square = curr_board[current_pos->y - 1][current_pos->x - 97];
moves* poss_moves = NULL;
if (square != EMPTY){
if (playing_color == 'W'){
if (square == WHITE_R){
poss_moves = getRookMoves(playing_color, curr_board, current_pos);
}
else if (square == WHITE_N){
poss_moves = getKnightMoves(playing_color, curr_board, current_pos);
}
else if (square == WHITE_B){
poss_moves = getBishopMoves(playing_color, curr_board, current_pos);
}
else if (square == WHITE_Q){
poss_moves = getQueenMoves(playing_color, curr_board, current_pos);
}
else if (square == WHITE_K){
poss_moves = getKingMoves(playing_color, curr_board, current_pos);
}
else {
poss_moves = getPawnMoves(playing_color, curr_board, current_pos);
}
}
else {
if (square == BLACK_R){
poss_moves = getRookMoves(playing_color, curr_board, current_pos);
}
else if (square == BLACK_N){
poss_moves = getKnightMoves(playing_color, curr_board, current_pos);
}
else if (square == BLACK_B){
poss_moves = getBishopMoves(playing_color, curr_board, current_pos);
}
else if (square == BLACK_Q){
poss_moves = getQueenMoves(playing_color, curr_board, current_pos);
}
else if (square == BLACK_K){
poss_moves = getKingMoves(playing_color, curr_board, current_pos);
}
else {
poss_moves = getPawnMoves(playing_color, curr_board, current_pos);
}
}
}
return poss_moves;
}
/*
* Getting all possible moves for a current player
*/
moves* getAllMoves(char playing_color, char curr_board[BOARD_SIZE][BOARD_SIZE]){
moves* all_moves = NULL;
position* curr_pos = NULL;
moves* pos_moves = NULL;
move* temp_head = NULL;
all_moves = calloc(1, sizeof(moves));
validate(all_moves, "getMoves");
for (int i = 0; i < BOARD_SIZE; i++){
for (int j = 0; j < BOARD_SIZE; j++){
curr_pos = calloc(1, sizeof(position));
validate(curr_pos, "getMoves");
initPosition(curr_pos, j + 97, i + 1);
if (isSameColor(playing_color, curr_pos, curr_board)){
pos_moves = getMovesFromPosition(playing_color, curr_board, curr_pos);
if (pos_moves->head != NULL){
temp_head = pos_moves->head;
concatMoves(all_moves, temp_head);
free(pos_moves);
}
}
freePositions(curr_pos);
}
}
return all_moves;
}
/*
* Getting all possible legal moves for a current player
*/
moves * getMoves(char playing_color, char curr_board[BOARD_SIZE][BOARD_SIZE]) {
moves * all_moves = getAllMoves(playing_color, curr_board);
removeBadMoves(all_moves, playing_color, curr_board);
return all_moves;
}
/*
* Checking if the game has ended in a Tie
*/
int isTie(char playing_color){
moves* possible_moves = getMoves(playing_color, board);
if (possible_moves->head == NULL && !isCheck(OppositeColor(playing_color),board)){
free(possible_moves);
return 1;
}
freeMoves(possible_moves->head);
free(possible_moves);
return 0;
}
/*
* Checking if the game has ended in a Mate or a Tie
*/
int gameOver(int print_bit){
if (isMate('W', board)){
if (print_bit){
printf("Mate! White player wins the game\n");
}
return 1;
}
if (isMate('B', board)){
if (print_bit){
printf("Mate! Black player wins the game\n");
}
return 1;
}
if (isTie('W') || isTie('B')){
if (print_bit){
printf("The game ends in a tie\n");
}
return 1;
}
return 0;
}
这是我执行的valgrind测试的日志 (所有泄漏都包含几乎相同的函数链,所以我只发布其中几个):
==28961== HEAP SUMMARY:
==28961== in use at exit: 80,480 bytes in 5,030 blocks
==28961== total heap usage: 124,076 allocs, 119,046 frees, 2,096,919 bytes allocated
==28961==
==28961== Searching for pointers to 5,030 not-freed blocks
==28961== Checked 1,055,792 bytes
==28961== 16 bytes in 1 blocks are definitely lost in loss record 5 of 152
==28961== at 0x4C2CC70: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==28961== by 0x40AD14: getBishopMoves (chesslogic.c:712)
==28961== by 0x40B745: getQueenMoves (chesslogic.c:877)
==28961== by 0x40C779: getMovesFromPosition (chesslogic.c:1056)
==28961== by 0x40C974: getAllMoves (chesslogic.c:1109)
==28961== by 0x40C9FF: getMoves (chesslogic.c:1126)
==28961== by 0x40CA3C: isTie (chesslogic.c:1136)
==28961== by 0x409BBD: gameOver (chesslogic.c:273)
==28961== by 0x40917B: SettingsMode (gameflow.c:626)
==28961== by 0x40CFBB: main (main.c:26)
==28961==
==28961== 16 bytes in 1 blocks are definitely lost in loss record 6 of 152
==28961== at 0x4C2CC70: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==28961== by 0x40BF47: getKingMoves (chesslogic.c:966)
==28961== by 0x40C79E: getMovesFromPosition (chesslogic.c:1059)
==28961== by 0x40C974: getAllMoves (chesslogic.c:1109)
==28961== by 0x40C9FF: getMoves (chesslogic.c:1126)
==28961== by 0x40CA3C: isTie (chesslogic.c:1136)
==28961== by 0x409BBD: gameOver (chesslogic.c:273)
==28961== by 0x40917B: SettingsMode (gameflow.c:626)
==28961== by 0x40CFBB: main (main.c:26)
==28961==
==28961== 16 bytes in 1 blocks are definitely lost in loss record 7 of 152
==28961== at 0x4C2CC70: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==28961== by 0x40AD14: getBishopMoves (chesslogic.c:712)
==28961== by 0x40B745: getQueenMoves (chesslogic.c:877)
==28961== by 0x40C84E: getMovesFromPosition (chesslogic.c:1077)
==28961== by 0x40C974: getAllMoves (chesslogic.c:1109)
==28961== by 0x4099C9: isCheck (chesslogic.c:220)
==28961== by 0x40A6C4: removeBadMoves (chesslogic.c:604)
==28961== by 0x40CA19: getMoves (chesslogic.c:1127)
==28961== by 0x40CA3C: isTie (chesslogic.c:1136)
==28961== by 0x409BBD: gameOver (chesslogic.c:273)
==28961== by 0x40917B: SettingsMode (gameflow.c:626)
==28961== by 0x40CFBB: main (main.c:26)
==28961==
==28961== 16 bytes in 1 blocks are definitely lost in loss record 8 of 152
==28961== at 0x4C2CC70: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==28961== by 0x40BF47: getKingMoves (chesslogic.c:966)
==28961== by 0x40C870: getMovesFromPosition (chesslogic.c:1081)
==28961== by 0x40C974: getAllMoves (chesslogic.c:1109)
==28961== by 0x4099C9: isCheck (chesslogic.c:220)
==28961== by 0x40A6C4: removeBadMoves (chesslogic.c:604)
==28961== by 0x40CA19: getMoves (chesslogic.c:1127)
==28961== by 0x40CA3C: isTie (chesslogic.c:1136)
==28961== by 0x409BBD: gameOver (chesslogic.c:273)
==28961== by 0x40917B: SettingsMode (gameflow.c:626)
==28961== by 0x40CFBB: main (main.c:26)
答案 0 :(得分:1)
正在释放player_moves
中的isCheck
指针。
valgrind输出实际上是指向你在calloc
中使用getBishopMoves
进行的分配(你没有发布的内容),所以你应该在那里寻找原因。记忆泄漏。
你还没有发布moves
数据类型是什么,但是如果它是一个包含你在getBishopMoves
中分配内存的指针的结构,那么在释放结构指针本身之前你应该释放该指针
类似的东西:
free(player_moves->ptr);
free(player_moves);
答案 1 :(得分:0)
我的代码丢失了,所以我只能猜到。另外,我不认为stackoverflow通常用于外包代码的调试。
但是,我认为问题在于player_moves是某种链表结构,包含许多已分配的结构(在getAllMoves中分配)。 free()只会释放player_moves对象,并且会导致泄漏,因为该结构中引用的指针会丢失。你应该创造一个“毁灭”的东西。通过并删除与其相关的每个移动的结构的功能。也许这已经排成一行freePositions(curr_pos)
,我无法从这个片段中说出来。这取决于freePositions
和concatMoves
正在做什么。
一般来说,我认为你已经陷入了这种束缚中,不遵循“创造它的人”会摧毁它。原理。在像C ++这样的OO语言中更容易构造,但在这种情况下,我将使用函数来创建和销毁对象(移动,碎片等)并在预先创建的情况下传递它们。例如,内部分配内存的getMovesFromPosition
函数并不明显。如果它接受了一个已分配的对象,则更清楚的是它需要在之后删除。
答案 2 :(得分:0)
只需评论你的freePositions()和freeMoves()函数。这里有不必要的递归使用。迭代地执行它会更有效率。
void freePositions(position* pos){
while (pos != NULL){
position *next = pos->next;
free(pos);
pos = next;
}
}
void freeMoves(move* move){
while (move != NULL){
move *next = move->next;
freePositions(move->current_pos);
if (move->promotion != NULL){
free(move->promotion);
}
free(move);
move = next;
}
}