gpt4 book ai didi

c - 从c中的第一个位置删除节点时出错

转载 作者:太空宇宙 更新时间:2023-11-04 07:02:08 26 4
gpt4 key购买 nike

正如我之前的许多帖子所显示的,我正在编写一个代码来模拟疯狂8的纸牌游戏。我有一个删除节点的功能,这意味着从正在播放的牌组中删除牌。它适用于第一张之后的卡片,但是每次我试图从列表中删除第一张卡片(节点)时,它都不会删除,然后在删除之后会弄乱整个程序。功能如下:

void deleteNode(card *head, int coordinate) {

card *current = head;
card *temp = NULL;
temp = current;
int count = 1;
while (head != NULL) {
if (coordinate == 0) {
current = current->listp;
free(temp);
break;
}
else if (count == coordinate) {
temp = current->listp;
current->listp = current->listp->listp;
free(temp);
break;
}
else {
count++;
current = current->listp;
}
}
}

头部进入的是正在演奏的手的顶部。坐标是用户想玩的牌的号码。例如,如果他们牌组中的第一张牌是红桃Q,这是他们想要玩的,他们就会进入一张。在函数调用中,我从用户选择中减去一个,这样它将与列表匹配(因为列表从0开始)。任何帮助都将不胜感激。我不能继续我的项目,直到我得到解决这个问题!

最佳答案

如注释中所述,您遇到的问题是由于没有将列表的地址传递给deleteNode函数。这个问题是最基本的,但却吸引了很多人。链表的地址,是第一个节点的地址。因此,删除第一个节点时,必须将新的列表地址设置为下一个节点地址,列表才能继续运行。
当您将指针传递给函数时,例如void deleteNode(card *head, ...,函数deleteNode将接收指针head的副本。副本有一个自己的地址,该地址与调用函数中返回的指针的地址没有关系。指针的值在deleteNode中与调用者中相同,但地址完全不同。
删除deleteNode中的第一个节点时会出现问题。内存是free'd,deleteNode函数返回。现在回到呼叫端(可能是main()),下次您尝试访问head——bam!塞格法特。为什么?head的地址从未在main中更新,因此它仍然指向原始节点——您刚才在deleteNode中对原始节点的内存做了什么?(您在一个指针上调用了free,该指针指向保存第一个节点的内存块——它已经消失……)
要解决此问题,只需将列表的地址(head)传递给deleteNode。(例如void deleteNode(card **head, ...)。然后在head的地址上操作(例如指向指针头的指针)。现在,在删除第一个节点之前,您可以设置*head = head->listp;并将新的列表地址反射回调用函数(main())。例如,您的代码可以编写为:

void delnode (card **head, int coordinate)
{
card *current = *head;
card *victim = NULL;
victim = current;
int count = 1;

while (current != NULL) {
if (coordinate == 0) {
*head = current->listp;
free (victim);
break;
}
else if (count == coordinate) {
victim = current->listp;
current->listp = current->listp->listp;
free (victim);
break;
}
else {
count++;
current = current->listp;
}
}
}

但是,您可以对函数的逻辑进行一些改进,只需很少的努力。例如
void delnode (card **head, int coordinate)
{
card *current = *head;
card *victim = current;
int count = 1;

if (coordinate == 0) {
*head = current->listp;
free (victim);
return;
}

while (current != NULL)
{
if (count == coordinate) {
victim = current->listp;
current->listp = current->listp->listp;
free (victim);
return;
}
count++;
current = current->listp;
}
}

最后,访问描述 How to Ask a QuestionHow to create a Minimal, Complete, and Verifiable example的链接。提供必要的详细信息,包括您的代码和相关的错误(如果有),将允许这里的每个人帮助您解决问题。
这个问题就是一个很好的例子。对于任何帮助您并实际编译和确认问题或答案的人,您要求这里的人编写一个示例程序,对您的基本列表结构进行合理的猜测。当您在这里提出问题时,提供MCVE的目的是让其他人可以编译您的代码并确认您遇到的问题,如果需要,可以通过调试器运行编译的代码以帮助您。如果你遵循网站上帮助我们帮助你的最小建议和规则,你会得到更多的帮助和积极的回应。
也就是说,您可以用这一小段示例代码来确认删除操作。
#include <stdio.h>
#include <stdlib.h>

typedef struct card {
int cardno;
struct card *listp;
} card;

card *createnode (int c);
card *insert (card **list, int c);
void prnlist (card *list);
void delnode (card **head, int coordinate);
void dellist (card *list);
void *xcalloc (size_t nmemb, size_t sz);

int main (void) {

card *list = NULL;

insert (&list, 18); /* insert test nodes */
insert (&list, 6);
insert (&list, 54);
insert (&list, 12);
insert (&list, 60);
insert (&list, 30);

printf ("\noriginal list:\n");
prnlist (list);

printf ("\ndeleting node: 2\ndeleting node: 0\n");
delnode (&list, 2); /* delete 3rd & 1st nodes */
delnode (&list, 0);

printf ("\nfinal list:\n");
prnlist (list);

dellist (list); /* free allocated memory */

return 0;
}

card *createnode (int c)
{
card *node = xcalloc (1, sizeof *node);

node->listp = NULL;
node->cardno = c;

return node;
}

card *insert (card **list, int c)
{
card *iter = *list;
card *node = createnode (c);

if (!*list) { /* add 1st node to list */
*list = node;
return *list;
}

/* insert all other nodes at end */
for (; iter->listp; iter = iter->listp) {}

iter->listp = node;

return *list;
}

void prnlist (card *list)
{
card *iter = list;
for (; iter->listp; iter = iter->listp)
printf (" cardno : %d\n", iter->cardno);
printf (" cardno : %d\n", iter->cardno);
}

void delnode (card **head, int coordinate)
{
card *current = *head;
card *victim = current;
int count = 1;

if (coordinate == 0) {
*head = current->listp;
free (victim);
return;
}

while (current != NULL)
{
if (count == coordinate) {
victim = current->listp;
current->listp = current->listp->listp;
free (victim);
return;
}
count++;
current = current->listp;
}
}

void dellist (card *list)
{
card *iter = list;
while (iter) {
card *victim = iter;
iter = iter->listp;
free (victim);
}
}

void *xcalloc (size_t nmemb, size_t sz)
{
void *memptr = calloc (nmemb, sz);

if (!memptr) {
fprintf (stderr, "xcalloc() error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}

return memptr;
}

示例使用/输出
$ ./bin/lldelcard

original list:
cardno : 18
cardno : 6
cardno : 54
cardno : 12
cardno : 60
cardno : 30

deleting node: 2
deleting node: 0

final list:
cardno : 6
cardno : 12
cardno : 60
cardno : 30

内存错误检查
在动态分配内存的任何代码中,对于分配的任何内存块,您都有两个职责:(1)始终保留指向内存块起始地址的指针,以便(2)在不再需要时可以释放它。
必须使用内存错误检查程序,以确保没有在已分配的内存块之外写入数据,尝试读取未分区的值或在未分区的值上进行跳转,最后确认已释放已分配的所有内存。
对于Linux valgrind是正常的选择。有很多微妙的方法可以滥用新的内存块。使用内存错误检查器可以识别任何问题,并验证您分配的内存的正确使用,而不是通过 segfault发现问题。每个平台都有类似的内存检查程序。它们都很容易使用,只要运行你的程序就可以了。
$ valgrind ./bin/lldelcard
==9094== Memcheck, a memory error detector
==9094== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==9094== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==9094== Command: ./bin/lldelcard
==9094==

original list:
cardno : 18
cardno : 6
cardno : 54
cardno : 12
cardno : 60
cardno : 30

deleting node: 2
deleting node: 0

final list:
cardno : 6
cardno : 12
cardno : 60
cardno : 30
==9094==
==9094== HEAP SUMMARY:
==9094== in use at exit: 0 bytes in 0 blocks
==9094== total heap usage: 6 allocs, 6 frees, 96 bytes allocated
==9094==
==9094== All heap blocks were freed -- no leaks are possible
==9094==
==9094== For counts of detected and suppressed errors, rerun with: -v
==9094== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)

始终确认释放了所有堆块——不可能有泄漏,同样重要的错误摘要:0个上下文中的0个错误。
祝你编码顺利。

关于c - 从c中的第一个位置删除节点时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36731270/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com