分配的内存由于某种原因未被释放 - C

时间:2015-08-27 13:08:12

标签: c memory-leaks valgrind allocation

我目前正在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)  

3 个答案:

答案 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),我无法从这个片段中说出来。这取决于freePositionsconcatMoves正在做什么。

一般来说,我认为你已经陷入了这种束缚中,不遵循“创造它的人”会摧毁它。原理。在像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;
    }
}