Освобождение памяти перешло в функцию - PullRequest
0 голосов
/ 22 сентября 2018

Я сейчас строю набор структур, которые будут хранить состояние игры uno.Игра хранится в структуре, которая содержит следующие данные.Я представляю колоду карт структурой под названием Deck, которая будет работать как стек, определенный следующим образом:

typedef struct _card *Card;
typedef struct _deck *Deck;
typedef struct _listCard *ListCard;
typedef struct _player *Player;

struct _card {
    value value;
    color color;
    suit suit;
};

struct _listCard {
    Card card;
    ListCard next;
};

struct _player {
    // Integer between 0 and 3.
    int player_id;
    //  Player has a hand (a deck of cards)
    Deck hand;
};

// A deck is an ADT for a linked lis of ListCards.
struct _deck {
    // Keep track of the deck.
    int num_cards;

    // Stack of cards in the deck.
    // Keep track of the top of the deck
    ListCard top;
};

struct _gamestate {
    int curr_player;
    int turn_number;
    Card curr_card;
};

struct _game {
    Deck draw_pile;
    Deck discard_pile;
    Player players;
    GameState game_state;
    int turnNumber;
    int deckSize;
};

Я реализовал несколько функций и сейчас пытаюсь написать функцию, которая удалитколода.

static void freeDeck(Deck deck) {
    ListCard curr = deck->top;
    if (curr == NULL) {
        free(deck);
        return;
    }
    while (curr != NULL) {
        ListCard temp = curr;
        destroyCard(temp->card);
        curr = curr->next;
        free(temp);
    }
    free(deck);
}

void destroyCard(Card card) {
    free(card);
}

Теперь у меня проблема с реализацией поп-функции и использованием возвращенного значения этой функции для перемещения карты из одной колоды в другую (например, взятие верхней карты колоды ипоместив его в стопку сброса).

static Card popCard(Deck deck) {
    // sanity check
    if (deck == NULL) {
        return NULL;

    // Can't pop from an empty stack.
    } else if (deck->top == NULL) {
        return NULL;

    // Only one card in the deck.
    } else if (deck->top->next == NULL) {
        Card temp = deck->top->card;
        free(deck->top);
        deck->top = NULL;

        return temp;
    }
    // Otherwise: at least two cards in the deck:

    Card val = deck->top->card;
    ListCard temp = deck->top->next;
    free(deck->top);
    deck->top = temp;
    return val;
}

Это моя функция для добавления, и это моя функция для добавления:

static void addToDeck(Deck deck, Card card) {
    if (deck->top == NULL) {
        deck->top = newListCard(card);
    } else {
        addCard(deck, card);
    }
    deck->num_cards++;
}

static ListCard newListCard(Card card) {
    ListCard newCard = malloc(sizeof(struct _listCard));
    newCard->next = NULL;
    newCard->card = card;
    return newCard;
}

static void addCard(Deck deck, Card card) {
    assert(deck != NULL);
    ListCard newCard = newListCard(card);
    newCard->next = deck->top;
    deck->top = newCard;
}

Я вызываю функцию для выполнения вышеуказанной операциивот так:

addToDeck(newgame->discard_pile, popCard(newgame->draw_pile));

Однако это приводит к ошибке неверного указателя в gdb, когда я пытаюсь освободить колоду с помощью

freeDeck(newgame->discard_pile)

Я новичок в управлении памятью C и считаю, чтопроблема связана с попыткой освободить память, которая больше не указывает на начало точки, где она была malloc'd.

РЕДАКТИРОВАТЬ:

Сама игра инициализируется так:

Game newGame(int deckSize, value values[], color colors[], suit suits[]) {
    // malloc a new game.
    Game newgame = malloc(sizeof(game));

    if (newgame == NULL) {
        fprintf(stderr, "Out of memory");
        return NULL;
    }
    // Otherwise there will be no cards to put into the draw pile.
    if (deckSize <= NUM_PLAYERS*DEFAULT_HAND) {
        return NULL;
    }

    newgame->deckSize = deckSize;

    // malloc the players in the game.

    Player players = malloc(NUM_PLAYERS*sizeof(struct _player));
    if (players == NULL) {
        fprintf(stderr, "Out of memory");
        return NULL;
    }

    // Instatiate each player object
    int i = 0;
    while (i < NUM_PLAYERS) {
        players[i].player_id = i;
        players[i].hand = newDeck();
        i++;
    }
    // Assign the players to the game.
    newgame->players = players;

    // Create decks of discard pile and draw_pile
    newgame->draw_pile = newDeck();
    newgame->discard_pile = newDeck();
    // loop through each of the values, colours and suits and create the necessary objects to star the game.

    i = 0;
    while (i < deckSize) {

        // Create a card from the array of values, colours and suits.
        Card card = newCard(values[i], colors[i], suits[i]);

        // Give each player 7 cards.
        if (i < DEFAULT_HAND*NUM_PLAYERS) {
            addToDeck(newgame->players[i % 4].hand, card);
        // After we have given each player seven cards fill the draw pile.
        } else {
            addToDeck(newgame->draw_pile, card);
        }

        i++;
    }

    // Push the first card onto the stack of the discard_pile.
    addToDeck(newgame->discard_pile, popCard(newgame->draw_pile));

    //Create the initial game state.

    GameState init = malloc(sizeof(struct _gamestate));
    init->curr_card = newgame->discard_pile->top->card;
    init->curr_player = 0;
    init->turn_number = 1;
    newgame->game_state = init;

    printGame(newgame);
    return newgame;
}

static Deck newDeck(void) {
    Deck deck = malloc(sizeof(struct _deck));

    if (deck == NULL) {
            fprintf(stderr, "Out of memory");
            return NULL;
    }

    deck->num_cards = 0;
    deck->top = NULL;
    return deck;
}

Игра освобождается с помощью этой функции:

void destroyGame(Game game) {
    GameState state = game->game_state;
    destroyCard(state->curr_card);
    free(state);
    Player players = game->players;
    int i = 0;
    while (i < NUM_PLAYERS) {
        freeDeck(players[i].hand);
        i++;
    }
    free(game->players);
    freeDeck(game->draw_pile);
    freeDeck(game->discard_pile);
    free(game);
}

Бесплатная функция работает, как и ожидалось, до тех пор, пока я не вызову freeDeck (game-> discard_pile), с помощью которого я получаю недопустимый указатель на элементчто я выскочил из колоды draw_pile.Еще одно тестирование показало, что это происходит каждый раз, когда я вытаскиваю карту из колоды.

Основная функция в данный момент просто вызывает следующее:

int main(void) {
    int decksize = 50;
    value values[decksize];
    color colors[decksize];
    suit suits[decksize];

    for (int i = 0; i < decksize; i++) {
            values[i] = rand() % 16;
            colors[i] = rand() % 16;
            suits[i] = rand() % 16;
    }
    Game cardgame = newGame(50, values, colors, suits);
    destroyGame(cardgame);
}

Где именно моя ошибка икак я могу это исправить?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...