【发布时间】:2022-01-19 23:06:39
【问题描述】:
我正在尝试编写一个扑克程序。现在几乎一切正常,一个问题是程序询问用户他们想要保留哪些卡片,以及他们想要丢弃哪些卡片。如果它按预期工作,用户将输入他们想要保留的卡片。没有被选中的卡片将被移除,并用牌组中的卡片替换。玩家的手牌和牌组是两个独立的链表。
这部分程序的行为有点奇怪。有时它工作正常。其他时候,它会丢弃本应保留的牌,或保留本应丢弃的牌。有时它也会改变某些牌的花色(或者可能是复制某些牌,我不确定)。
这是创建牌组的函数:
card *
createCard(int n)
{
int i = 0;
card *head = (card *) malloc(sizeof(card));
card *tmp = NULL;
card *p = NULL;
p = head;
for (i = 0; i < n - 1; i++) {
tmp = (card *) malloc(sizeof(card));
p->next = tmp;
p = p->next;
p->next = NULL;
}
tmp = head;
for (i = 1; i <= 13; i++) {
for (int j = 3; j <= 6; j++) {
tmp->face = i;
tmp->suit = j;
tmp = tmp->next;
}
}
return (head);
}
这是创建玩家手牌的函数(通过从套牌列表的前五个节点创建一个新的链表):
void
createHand(card ** deck, card ** hand)
{
card *tmp = NULL;
card *card = *deck;
int i;
//while (card != NULL)
for (i = 0; i < 5; i++) {
(*deck) = (*deck)->next;
tmp = card->next;
card->next = *hand;
*hand = card;
card = tmp;
}
(*hand)->next->next->next->next->next = NULL;
return;
}
这是不起作用的代码部分(注意:playerHand 是玩家的手,首先是牌组):
i = 1;
// this array keeps track of which cards the user wants to keep
int a[] = { 0, 0, 0, 0, 0 };
while (i <= 5) {
printf("Pick cards (between 1-5) to hold (-1 to stop): ");
scanf("%d", &keep);
// breaks from loop if the user enters -1
if (keep == -1)
break;
if (keep == 0 || keep > 5 || keep <= -2) {
printf("Invalid index. Pick cards (between 1-5) to hold (-1 to stop): ");
scanf("%d", &keep);
if (keep == -1)
break;
}
if (keep == -1) {
break;
}
if (keep != -1) {
// when player wants to keep a card, the corresponding index of that
// card is set to one in the array
a[keep - 1] = 1;
}
i++;
}
card *tmp;
tmp = first;
card *tmp2;
tmp2 = playerHand;
for (i = 0; i < 5; i++) {
// if the corresponding index in the array is 0, that card is replaced
if (a[i] == 0) {
tmp2->face = tmp->face;
tmp2->suit = tmp->suit;
}
first = first->next;
free(tmp);
tmp = first;
tmp2 = tmp2->next;
}
删除这部分代码后,卡片并没有改变,所以错误一定在哪里,我只是不确定在哪里。
这是玩家选择要保留的卡片时的输出结果。在这种情况下,玩家选择保留第一张和第三张牌并丢弃其他三张:
选择卡(1-5 之间)持有(-1 停止):1
选择卡(1-5 之间)持有(-1 停止):3
选择卡片(1-5 之间)持有(-1 停止):-1
【问题讨论】:
-
您是否尝试过在调试器中逐行运行代码,同时监控所有变量的值,以确定您的程序在哪个点停止按预期运行?如果您没有尝试过,那么您可能想阅读以下内容:What is a debugger and how can it help me diagnose problems? 您可能还想阅读以下内容:How to debug small programs?。
-
请注意,在调试生成随机值的程序时,使用固定值播种随机数生成器通常很有帮助,而不是每次运行程序时都使用不同的值。这样,您可以更轻松地重现特定错误,因为无论何时在调试器中重新启动程序,程序的行为都是相同的。
-
如果可能,请提供问题的minimal reproducible example(包括函数
main和所有#include指令)。例如,也许你可以为玩家的手牌和牌组提供一个简单的硬编码链表,并在上面演示问题。 -
你有 UB(未定义的行为)。在第三个代码块中,在
for循环中,您执行以下操作:tmp2->face = tmp->face;。但是,tmp已统一。它有一个“随机”值,所以它可以指向任何东西。通常,这会导致段错误。但是,对于 UB,如果tmp指向存在的内存,您可以获得随机结果,基于 whatever 只是“碰巧”在那里。你会希望tmp指向一张从牌组中拉出/出列的新牌。所以:在if下,你可以这样做:tmp = get_card_from_deck()。但是,这会“泄露”tmp指向的卡片...... -
... 最好让
tmp2出队/释放tmp,其中tmp2在玩家手牌列表中。我会编写执行低级任务的函数(例如):void list_append(list *lst,card *crd);和void list_remove(list *lst,card *crd);和void list_discard_and replace(list *lst,card *old,card *new);您可能需要一些列表:list discard_list, deck_list, player_hands[NPLAYERS];并且,将卡片移入/移出这些列表
标签: c linked-list