从链表中删除用户选择的节点,用 c 中另一个列表中的节点替换它们
Posted
技术标签:
【中文标题】从链表中删除用户选择的节点,用 c 中另一个列表中的节点替换它们【英文标题】:removing user chosen nodes from a linked list, replacing them with nodes from another list in c 【发布时间】: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];
并且,将卡片移入/移出这些列表
【参考方案1】:
也许代码应该是这样的?玩家如何选择替换卡?
你能展示保存卡片以供替换的代码是什么样的吗?
card *tmp;
tmp = first;
card *tmp2;
tmp2 = playerHand;
for (i = 0; i < 5; i++)
if (a[i] == 0) //if the corresponding index in the array is 0, that card is replaced
tmp2->face = tmp->face;
tmp2->suit = tmp->suit;
first = first->next;
free(tmp);
tmp = first;
tmp2 = tmp2->next;
用户选择要替换的卡片后,我们从牌组中取出前n张卡片。
您的代码中的错误是牌组的前五张牌总是被丢弃。如果手中的牌被标记为丢弃,则不是从牌堆中取出下一张牌,而是一张具有相同索引的牌。
card *tmp;
tmp = first;
card *tmp2;
tmp2 = playerHand;
for (i = 0; i < 5; i++)
// if the corresponding index in the array is 0,
// the card will be replaced by a card with the same index from the deck
if (a[i] == 0)
tmp2->face = tmp->face;
tmp2->suit = tmp->suit;
first = first->next; //changes the top of the deck to the next
free(tmp); //always removes a card from the deck
//so the first 5 cards will be removed
tmp = first; //all these three lines must be moved to the condition if
tmp2 = tmp2->next;
而在while循环中,需要改代码,因为如果用户连续两次输入错误的索引,程序就会crash
if (keep == 0 || keep > 5 || keep <= -2)
printf("Invalid index. ");
continue;
【讨论】:
以上是关于从链表中删除用户选择的节点,用 c 中另一个列表中的节点替换它们的主要内容,如果未能解决你的问题,请参考以下文章