在程序执行的某个点出现一致的内存访问错误(-1073741819(0xC0000005))

问题描述 投票:0回答:1

我目前正在尝试用 C++ 构建一个包含几轮的简单游戏。不幸的是,出于某种原因,在整整三轮之后,我一直遇到内存访问冲突并且程序崩溃,我只是想不通为什么,所以非常感谢任何帮助。

仅供参考:代码看起来更像 C 而不是 C++,因为到目前为止我只接触过 C,而且我才刚刚开始学习 C++。下周我将不得不用类而不是结构编写相同的程序。

我认为问题可能在于我在每轮之后再次释放和动态分配的竞技场。

玩家和对手的结构数组在每场比赛开始时分配。

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <limits>

struct arena{
    int game_map[5][5];
};

struct character{
    int life_points = 5;
    int relic_counter = 0;
    int total_relics = 0;
    int maps_cleared = 0;
    int x = 0;
    int y = 0;
};

struct opponent{
    int last_field;
    int x;
    int y;
};

void flush_input();
bool input_game();
void check_next_field(struct arena* arena, struct character* player, char nex_field, bool* player_dead);
void input_movement(struct arena* arena, struct character* player, bool* player_dead);
void opponent_movement(struct arena* arena, struct opponent* opponent_array, int opponent_num, bool* player_dead);
void initialize_player(struct character* player);
void create_arena(struct arena*);
void spawn_opponent(struct arena*, struct opponent* opponent_array, int opponent_num);
int relic_counter(struct arena* arena);
void print_arena(struct arena*);
void update_arena_mask(struct arena* arena, char arena_mask[][5]);
void print_arena_mask(char arena_mask[][5]);

int main()
{
    //allocates memory for a new player and initializes them
    struct character* player = (struct character*)malloc(sizeof(struct character));
    initialize_player(player);

    struct opponent* opponent_array = (struct opponent*)malloc(10 * sizeof(struct opponent));

    bool first_game = true;
    bool play_again = true;
    bool player_dead = false;

    char arena_mask[5][5];
    int relic_count_map = 0;

    srand((unsigned)time(NULL));

    while(play_again){
        //if the player died reinitialize character
        if(player_dead){
            initialize_player(player);
            player_dead = false;
        }

        //allocates memory for a new map/opponent
        struct arena* arena = (struct arena*)malloc(sizeof(struct arena));

        //initializes new map
        //checks if it contains at least one relic
        do{
            create_arena(arena);
            relic_count_map = relic_counter(arena);
        } while(relic_count_map == 0);

        //spawns opponents depending on the number of maps cleared
        for(int i = 0; i < (player->maps_cleared + 1); i++){
            spawn_opponent(arena, opponent_array, i);
        }

        update_arena_mask(arena, arena_mask);
        print_arena(arena);
        std::cout << std::endl;

        //game instructions
        if(first_game){
            std::cout << "WELCOME TO OASIS CRAWLER!" << std::endl;
            std::cout << "-------------------------" << std::endl;
            std::cout << "The goal of this game is to make it through as many maps as possible before your characters dies." << std::endl;
            std::cout << "You finish a map once you have collected all of its relics." << std::endl;
            std::cout << "'P' = PLAYER, 'D' = DANGER, 'W' = WELL, '?' = RELIC/DANGER, '!' = OPPONENT, '.' = EMPTY FIELD" << "\n" << std::endl;

            std::cout << "Map: " << (player->maps_cleared + 1) << std::endl;
            print_arena_mask(arena_mask);
            std::cout << "Life Points: " << player->life_points << "  " << "Relicts Collected: " << player->relic_counter << "/" << relic_count_map << "\n" << std::endl;
        }else{
            std::cout << "Map: " << (player->maps_cleared + 1) << std::endl;
            print_arena_mask(arena_mask);
            std::cout << "Life Points: " << player->life_points << "  " << "Relicts Collected: " << player->relic_counter << "/" << relic_count_map << "\n" << std::endl;
        }

        while(1){
            input_movement(arena, player, &player_dead);

            //checks if the player moved into an opponent
            if(player_dead){
                break;
            }

            //spawns opponents depending on the number of opponents cleared
            for(int i = 0; i < (player->maps_cleared + 1); i++){
                opponent_movement(arena, opponent_array, i, &player_dead);
            }

            //checks if an opponent moved into the player
            if(player_dead){
                break;
            }

            std::cout << "Map: " << (player->maps_cleared + 1) << "\n" << std::endl;
            update_arena_mask(arena, arena_mask);
            print_arena(arena);
            std::cout << std::endl;
            print_arena_mask(arena_mask);

            //check if all relics have been collected
            if(player->relic_counter == relic_count_map){
                break;
            }

            //check life points
            if(player->life_points <= 0){
                player_dead = true;
                break;
            }

            std::cout << "Life Points: " << player->life_points << "  " << "Relicts Collected: " << player->relic_counter << "/" << relic_count_map << "\n" << std::endl;
        }
        first_game = false;
        player->total_relics += player->relic_counter;
        player->relic_counter = 0;

        //checks if the player is dead, if not they are asked if they want to play another round
        if(!player_dead){
            std::cout << "\n" << "MAP CLEARED" << "\n" << std::endl;
            //updates character
            player->x = 0;
            player->y = 0;
            player->maps_cleared++;

            //clears all the opponents
            for(int i = 0; i < (player->maps_cleared + 1); i++){
                arena->game_map[opponent_array[i].y][opponent_array[i].x] = opponent_array[i].last_field;
            }

            //print out maps cleared and relics found
            std::cout << "Maps Cleared: " << player->maps_cleared << "  " << "Total Relics Collected: " << player->total_relics << "\n" << std::endl;
            play_again = input_game();
        }
        else{
            std::cout << "GAME OVER" << "\n" << std::endl;
            arena->game_map[player->y][player->x] = 6;
            update_arena_mask(arena, arena_mask);
            print_arena_mask(arena_mask);
            std::cout << "Maps Cleared: " << player->maps_cleared << "  " << "Total Relics Collected: " << player->total_relics << "\n" << std::endl;

            play_again = input_game();
        }

        //prints out end stats if the player isnt dead and doesnt want to play again
        if(!player_dead && !play_again){
            std::cout << "GAME OVER" << "\n" << std::endl;
            update_arena_mask(arena, arena_mask);
            print_arena_mask(arena_mask);
            std::cout << "Maps Cleared: " << player->maps_cleared << "  " << "Total Relics Collected: " << player->total_relics << "\n" << std::endl;
        }

        //frees arena if player doesnt want to continue
        if(!play_again){
            free(player);
            free(opponent_array);
            free(arena);
        }else{
            //frees memory for arena
            free(arena);
        }
    }
    return 0;
}

// discard all input up to the next line break
void flush_input(){
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

//asks the user if they want to play again, validates input, and returns bool value
bool input_game(){
    char input;

    while(1){
        std::cout << "Play again? (Y/N): ";
        std::cin >> input;
        input = tolower(input);

        if(input == 'y'){
            flush_input();
            std::cout << std::endl;
            return true;
        }
        else if(input == 'n'){
            flush_input();
            std::cout << std::endl;
            return false;
        }
        else{
            std::cout << "\nINVALID INPUT\n" << std::endl;
            flush_input();
        }
    }
}

/* TODO: linked list insert here */
//checks the next field the player moves to and updates player points accordingly
void check_next_field(struct arena* arena, struct character* player, int next_field, bool* player_dead){
    int damage;

    switch(next_field){
        //character finds danger field and has 1/6 chance to lose one life_point
        case 1:
            damage = (rand() % 6) + 1;

            if(damage == 1){
                player->life_points--;
            }
            break;
        //character finds well and gains 1 life_point unless he is already at max health
        case 2:
            if(player->life_points != 5){
                player->life_points++;
            }
            break;
        //character finds relict and relict counter is updated
        case 3:
            player->relic_counter++;
            break;
        //character finds opponent and dies
        case 5:
            *player_dead = true;
            break;
        //character finds nothing
        default:
            break;
    }
}

void input_movement(struct arena* arena, struct character* player, bool* player_dead){
    char input;
    int next_field;
    bool valid_input = false;

    //checks if the character movement fit in the arena array
    while(!valid_input){
        //checks if the player's input is valid
        while(1){
            std::cout << "Please enter your characters next move! (WASD): ";
            std::cin >> input;
            input = tolower(input);

            if(input == 'w' || input == 's' || input == 'a' || input == 'd'){
                flush_input();
                break;
            }
            else{
                std::cout << "\nINVALID INPUT" << "\n" << std::endl;
                flush_input();
            }
        }

        switch(input){
            //character moves up
            case 'w':
                //checks if the field the player moves to is in bounds of the arena
                if((player->y - 1) >= 0){
                    //clear the field the character is currently on
                    arena->game_map[player->y][player->x] = 0;
                    //checks the type of field the player moves
                    next_field = arena->game_map[player->y - 1][player->x];
                    //function updates player points depending on the type of field
                    check_next_field(arena, player, next_field, player_dead);
                    //changes the player position according to the user input
                    player->y--;
                    //verifies input
                    valid_input = true;
                }
                break;
            //character moves down
            case 's':
                if((player->y + 1) < 5){
                    arena->game_map[player->y][player->x] = 0;
                    next_field = arena->game_map[player->y + 1][player->x];
                    check_next_field(arena, player, next_field, player_dead);
                    player->y++;
                    valid_input = true;
                }
                break;
            //character moves down
            case 'a':
                if((player->x - 1) >= 0){
                    arena->game_map[player->y][player->x] = 0;
                    next_field = arena->game_map[player->y][player->x - 1];
                    check_next_field(arena, player, next_field, player_dead);
                    player->x--;
                    valid_input = true;
                }
                break;
            //character moves down
            case 'd':
                if((player->x + 1) < 5){
                    arena->game_map[player->y][player->x] = 0;
                    next_field = arena->game_map[player->y][player->x + 1];
                    check_next_field(arena, player, next_field, player_dead);
                    player->x++;
                    valid_input = true;
                }
                break;
        }
        //checks if the player made a valid moves and updates the game_map
        if(valid_input){
            arena->game_map[player->y][player->x] = 4;
        }
        else{
            std::cout << "\nOUT OF BOUNDS\n" << std::endl;
        }
    }
    std::cout << std::endl;
}

void opponent_movement(struct arena* arena, struct opponent* opponent_array, int opponent_num, bool* player_dead){
    int next_field;
    int last_field = opponent_array[opponent_num].last_field;
    bool valid_move = false;

    while(!valid_move){
        int random = (rand() % 4) + 1;

        switch(random){
            //opponent moves up
            case 1:
                //checks if the field the opponent moves to is in bounds of the arena
                if((opponent_array[opponent_num].y - 1) >= 0){
                    //turns last field back to the field it was before the opponent moved on it
                    arena->game_map[opponent_array[opponent_num].y][opponent_array[opponent_num].x] = last_field;
                    //checks the next field
                    next_field = arena->game_map[opponent_array[opponent_num].y - 1][opponent_array[opponent_num].x];

                    //checks if the next field is the player
                    if(next_field == 4){
                        *player_dead = true;
                    //checks if the next field is another opponent
                    }else if(next_field == 5){
                        break;
                    //if it is any other field, the next field is saved
                    //then the opponent moves to the next field
                    }else{
                        opponent_array[opponent_num].last_field = next_field;
                        opponent_array[opponent_num].y--;
                        arena->game_map[opponent_array[opponent_num].y][opponent_array[opponent_num].x] = 5;
                    }
                    valid_move = true;
                }
                break;
            //opponent moves down
            case 2:
                if((opponent_array[opponent_num].y + 1) < 5){
                    arena->game_map[opponent_array[opponent_num].y][opponent_array[opponent_num].x] = last_field;
                    next_field = arena->game_map[opponent_array[opponent_num].y + 1][opponent_array[opponent_num].x];

                    if(next_field == 4){
                        *player_dead = true;
                    }else if(next_field == 5){
                        break;
                    }else{
                        opponent_array[opponent_num].last_field = next_field;
                        opponent_array[opponent_num].y++;
                        arena->game_map[opponent_array[opponent_num].y][opponent_array[opponent_num].x] = 5;
                    }
                    valid_move = true;
                }
                break;
            //opponent moves left
            case 3:
                if((opponent_array[opponent_num].x - 1) >= 0){
                    arena->game_map[opponent_array[opponent_num].y][opponent_array[opponent_num].x] = last_field;
                    next_field = arena->game_map[opponent_array[opponent_num].y][opponent_array[opponent_num].x - 1];

                    if(next_field == 4){
                        *player_dead = true;
                    }else if(next_field == 5){
                        break;
                    }else{
                        opponent_array[opponent_num].last_field = next_field;
                        opponent_array[opponent_num].x--;
                        arena->game_map[opponent_array[opponent_num].y][opponent_array[opponent_num].x] = 5;
                    }
                    valid_move = true;
                }
                break;
            //opponent moves right
            case 4:
                if((opponent_array[opponent_num].x + 1) < 5){
                    arena->game_map[opponent_array[opponent_num].y][opponent_array[opponent_num].x] = last_field;
                    next_field = arena->game_map[opponent_array[opponent_num].y][opponent_array[opponent_num].x + 1];

                    if(next_field == 4){
                        *player_dead = true;
                    }else if(next_field == 5){
                        break;
                    }else{
                        opponent_array[opponent_num].last_field = next_field;
                        opponent_array[opponent_num].x++;
                        arena->game_map[opponent_array[opponent_num].y][opponent_array[opponent_num].x] = 5;
                    }
                    valid_move = true;
                }
                break;
        }
    }
}

//initializes a new character
void initialize_player(struct character* player){
    player->life_points = 5;
    player->maps_cleared = 0;
    player->relic_counter = 0;
    player->total_relics = 0;
    player->x = 0;
    player->y = 0;
}

//initializes the fields of the game_map with random numbers
void create_arena(struct arena* arena){
    for(int row = 0; row < 5; row++){
        for(int col = 0; col < 5; col++){
            int field = (rand() % 10) + 1;

            switch(field){
                //empty field
                case 1 ... 4:
                    arena->game_map[row][col] = 0;
                    break;
                //danger field
                case 5 ... 8:
                    arena->game_map[row][col] = 1;
                    break;
                //well field
                case 9:
                    arena->game_map[row][col] = 2;
                    break;
                //relict field
                case 10:
                    arena->game_map[row][col] = 3;
                    break;
            }
        }
    }
    //places character on the map
    arena->game_map[0][0] = 4;
}

void spawn_opponent(struct arena* arena, struct opponent* opponent_array, int opponent_num){
    while(1){
        int x = rand() % 5;
        int y = rand() % 5;

        //checks if the randomly generated spawn is not the players spawn or another opponent
        //updates the map
        if(x != 0 && y != 0){
            if(arena->game_map[y][x] != 5){
                opponent_array[opponent_num].last_field = arena->game_map[y][x];
                opponent_array[opponent_num].x = x;
                opponent_array[opponent_num].y = y;
                arena->game_map[y][x] = 5;
                break;
            }
        }
    }
}

//checks if the generated game_map contains at least one relict
int relic_counter(struct arena* arena){
    int relic_counter = 0;

    for(int row = 0; row < 5; row++){
        for(int col = 0; col < 5; col++){
            if(arena->game_map[row][col] == 3){
                relic_counter++;
            }
        }
    }
    return relic_counter;
}

//update arena mask
void update_arena_mask(struct arena* arena, char arena_mask[][5]){
    int hidden;

    for(int row = 0; row < 5; row++){
        for(int col = 0; col < 5; col++){
            int field = arena->game_map[row][col];

            switch(field){
                //danger field, chance that it is hidden
                case 1:
                    hidden = rand() % 2;

                    if(hidden == 0){
                        arena_mask[row][col] = 'D';
                    }
                    else{
                        arena_mask[row][col] = '?';
                    }
                    break;
                //well
                case 2:
                    arena_mask[row][col] = 'W';
                    break;
                //relict
                case 3:
                    arena_mask[row][col] = '?';
                    break;
                //player
                case 4:
                    arena_mask[row][col] = 'P';
                    break;
                //opponent
                case 5:
                    arena_mask[row][col] = '!';
                    break;
                //player died
                case 6:
                    arena_mask[row][col] = 'X';
                    break;
                //empty field
                default:
                    arena_mask[row][col] = '.';
                    break;
            }
        }
    }
}

//prints arena
void print_arena(struct arena* arena){
    for(int row = 0; row < 5; row++){
        for(int col = 0; col < 5; col++){
            std::cout << arena->game_map[row][col] << " ";
        }
        std::cout << std::endl;
    }
}

//prints arena mask
void print_arena_mask(char arena_mask[][5]){
    for(int row = 0; row < 5; row++){
        std::cout << "\t";
        for(int col = 0; col < 5; col++){
            std::cout << "  " << arena_mask[row][col] << "  ";
        }
        std::cout << "\n" << std::endl;
    }
}
c++ memory-management
1个回答
0
投票

您可能两次释放“竞技场”,这可能会导致双重释放:

    /* FREE MEMORY ARENA */
    //frees memory for arena
    free(arena);

    /* FREE MEMORY PLAYER; STRUCT ARRAY; ARENA */
    //frees arena if player doesnt want to continue
    if(!play_again){
        free(player);
        free(opponent_array);
        free(arena);
    }

更新:

你可能错误地分配了'opponent_array',看:

  /* ALLOCATE MEMORY STRUCT ARRAY */
  struct opponent *opponent_array = (struct opponent *)malloc(10 * sizeof(struct opponent *));

显然需要一个包含 10 个对手的数组,但将包含 10 个指针的数组分配给了对手。上帝保佑你,你有

struct opponent
12 字节大小,而 64 位系统中的指针(虚拟地址)可能是 8 字节长度。所以你期望分配 120 个字节但实际上分配了 80

我希望这段代码是

  /* ALLOCATE MEMORY STRUCT ARRAY */
  struct opponent *opponent_array = (struct opponent *)malloc(10 * sizeof(struct opponent));

看看

© www.soinside.com 2019 - 2024. All rights reserved.