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

标签 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)  

最佳答案

正在释放 isCheck 中的 player_moves 指针。

valgrind 输出实际上指向您在 getBishopMoves 中使用 calloc 进行的分配(您尚未发布的内容),所以这就是您应该在的位置查找内存泄漏的原因。

您还没有发布 moves 数据类型是什么,但如果它是一个包含您在 getBishopMoves 中分配内存的指针的结构,那么您应该释放该指针在释放结构指针本身之前。

类似于:

free(player_moves->ptr);
free(player_moves);

关于c - 由于某种原因分配的内存未释放 - C,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32250269/

相关文章:

c - lowlevellock 和无限 While 循环

java - 字节流/C/JNI

c++ - *bool 数组是否被正确删除 C++

database - RabbitMQ 内存使用

C++ 内存错误 : free(): invalid next size (fast)

c - 将字符串数组覆盖在字符数组上

c - 取消引用和后缀的优先级

Delphi - 如何从 TDataSet 中释放内存?

MySQL C API内存泄漏?

c - libxml2:xmlNewTextWriterFilename 泄漏