Перемешивание указателей на указатели на структуры - PullRequest
0 голосов
/ 18 сентября 2018

В моем коде 2 структуры;card(value, suit) и deck(**cards, n), и я пытаюсь перетасовать карты внутри колоды.

Внутри цикла for функции shuffle().

i-я карта после первой картысохраняется в temp_card.

Случайная карта выбирается и присваивается i-й карте.

temp_card назначено случайной карте.

Проблема в том, что программа останавливает выполнение на этой строке, возможно, из-за ошибки сегментации.

**(d->cards + i) = **(d->cards + random_number);

Я попытался отладитьс GDB, но это не было очень конкретным.Это код.Я также добавил несколько карт и колоды в main(), чтобы протестировать его, но я довольно плохо знаком с C, так что я мог бы также испортить места в памяти этих указателей.

Правильный ли мой подход к тасованиюили я должен изменить его, и почему программа останавливается на этой строке, потому что указанные мной указатели недействительны?

#include <stdio.h>
#include <stdlib.h>

#define VALUE_ACE 14
#define VALUE_KING 13
#define VALUE_QUEEN 12
#define VALUE_JACK 11

typedef enum {
  SPADES,
  HEARTS,
  DIAMONDS,
  CLUBS,
  NUM_SUITS
} suit_t;

struct card_tag {
  unsigned value;
  suit_t suit;
};
typedef struct card_tag card_t;

struct deck_tag {
  card_t ** cards;
  size_t n_cards;
};
typedef struct deck_tag deck_t;

void shuffle(deck_t * d){   

    card_t temp_card;
    int n = d->n_cards;
    int random_number;

    for (int i = 0; i < n; i++){

        temp_card = **(d->cards + i);

        random_number = rand() % n;

        **(d->cards + i) = **(d->cards + random_number);
        **(d->cards + random_number) = temp_card;
    }       
}

int main(){
    deck_t deck;

    card_t card1;
    card1.suit = 1;
    card1.value = 1;
    card_t *c_ptr = &card1;
    card_t **c_pptr = &c_ptr;

    card_t card2;
    card2.suit = 2;
    card2.value = 2;
    card_t *c_ptr2 = &card2;
    card_t **c_pptr2 = &c_ptr2;

    card_t card3;
    card3.suit = 0;
    card3.value = 5;
    card_t *c_ptr3 = &card3;
    card_t **c_pptr3 = &c_ptr3;

    card_t card4;
    card4.suit = 2;
    card4.value = 2;
    card_t *c_ptr4 = &card4;
    card_t **c_pptr4 = &c_ptr4;

    deck.cards = c_pptr;

    deck.n_cards = 4;

    deck_t *d_ptr = &deck;

    shuffle(d_ptr); 
}

Ответы [ 2 ]

0 голосов
/ 18 сентября 2018

Как уже отмечалось в комментарии (от Barmar & Weather Vane), ваш код не вставляет 4 карты в колоду.Вставляется только первая карта, а остальные три карты не имеют отношения к колоде.

Вам нужно использовать динамическое распределение, чтобы вы могли распределить массив карт.Размер массива должен соответствовать количеству карт в колоде.

Но сначала ... Кажется странным использовать двойной указатель в колоде.Так что начните с изменения его в «одиночный» указатель - как:

struct deck_tag {
  card_t * cards; // Only one *
  size_t n_cards;
};

Затем в main сделайте что-то вроде:

int main(){
    deck_t deck;
    deck.n_cards = 4;
    deck.cards = malloc(deck.n_cards * sizeof *deck.cards);
    if (!deck.cards) exit(1);

    // Now you have 4 cards in the deck and you can 
    // insert card values directly into the deck.
    // There is no need for variables like card1, card2, card3 ...
    deck.cards[0].suit = 1;
    deck.cards[0].value = 1;

    deck.cards[1].suit = 2;
    deck.cards[1].value = 2;

    ... and so on (or better... use loops)


    shuffle(d_ptr); 

    free(deck.cards);
    return 0;
}

Также вам нужно обновить shuffleкод для использования «одиночного» указателя.

0 голосов
/ 18 сентября 2018

Вы назначаете карточки с помощью deck.cards = c_pptr, но c_pptr является только указателем на первый указатель карточки.Тем не менее, вы предполагаете, что cards + i волшебным образом найдет другие указатели карт, связанные с этим первым указателем карты, но ничто в коде не поддерживает это.Используя аналогию с картами: у вас есть четыре карты, разбросанные в разных местах, вы берете одну из этих карт, а затем ожидаете, что сможете взять следующую карту из этой «колоды», но у вас есть только одна карта.

Чтобы индексирование (с *(cards + i) или эквивалентным cards[i]) работало, вам нужно выделить массив для указателей на карточки, заполнить эти указатели адресами ваших карточек и назначитьуказатель на первый элемент массива указателей карты на cards.Массив, такой как card_t *card_ptrs[4], - это то, что делает индексирование работающим - содержимое последовательно в памяти, мало чем отличается от карт в колоде.

Однако второй слой указателей не нужен: вы можете просто выделитьмассив карт (не указатели на карты) и назначьте указатель на первую карту на cards (удалив вторую * из нее и из всех других мест, где она у вас есть).

...