【问题标题】:Shuffling pointers to pointers to structs将指针改组为指向结构的指针
【发布时间】:2018-09-18 12:51:37
【问题描述】:

我的代码中有 2 个结构; card(value, suit)deck(**cards, n),我正在尝试洗牌。

shuffle() 函数的 for 循环内。

第一张卡片之后的第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); 
}

【问题讨论】:

  • 您只将一张卡片放入deck.cards,而不是全部四张卡片。
  • deck.cards = c_pptr; 牌组中只有一张牌。为什么需要双 * 指针?
  • 旁白:在使用enum 定义套装后,您忽略它并使用01 等。
  • @WeatherVane 这是一个课程作业,我应该使用指向指针的指针来执行此操作,那么如何像数组一样将这些指针添加到第一张卡片之后的牌组?
  • 您可能需要card_t struct 的数组并将deck_t struct 中的数组地址存储在单指针而不是双指针中。

标签: c pointers struct segmentation-fault shuffle


【解决方案1】:

正如评论中已经指出的那样(来自 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;
}

您还需要更新随机播放代码以使用“单一”指针。

【讨论】:

  • 我对双精度也不太满意,但课程强制我这样做是为了教如何洗牌指针地址
  • @gunessun 你是说不允许更改struct deck_tag?如果是这样,那么该信息(即struct deck_tag 必须使用双指针)应该是您问题的一部分。对于这个特定的应用程序,我看不到使用双指针的任何目的/好处。因此,我的建议是摆脱它们,而使用更简单的方法。在某些情况下,使用双指针和“洗牌”指针而不是洗牌元素是有意义的,但这不是一个。
【解决方案2】:

您使用deck.cards = c_pptr 分配卡,但c_pptr 只是指向第一张卡指针的指针。然而,您假设cards + i 会神奇地找到与第一个卡指针相关的其他卡指针指针,但代码中没有任何内容支持这一点。打个比方:你有四张牌分散在不同的地方,你拿了其中一张牌,然后你希望能够从那个“牌组”中抽出下一张牌,但你只拿着一张牌。

为了使索引(使用*(cards + i) 或等效的cards[i])起作用,您需要为指向卡片的指针分配一个数组,用卡片的地址填充这些指针,然后将指向卡指针数组的第一个元素的指针分配给cards。数组,例如 card_t *card_ptrs[4],是索引工作的原因 - 内容在内存中是连续的,与卡片组中的卡片不同。

然而,第二层指针是不必要的:你可以只分配一个 cards 数组(不是指向卡片的指针)并将指向第一张卡片的指针分配给cards(删除第二张卡片) * 来自它以及您拥有的所有其他地方)。

【讨论】:

  • (顺便说一句,不得不说“卡片指针”之类的东西通常是一个很好的指标,表明代码可能不必要地复杂。)
猜你喜欢
  • 2017-06-03
  • 2018-05-16
  • 1970-01-01
  • 1970-01-01
  • 2016-03-21
  • 2012-03-28
  • 1970-01-01
相关资源
最近更新 更多