Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/63.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 从链接列表中删除节点时遇到问题_C_Linked List - Fatal编程技术网

C 从链接列表中删除节点时遇到问题

C 从链接列表中删除节点时遇到问题,c,linked-list,C,Linked List,我一直在为我正在创建的shell编写这段代码,但由于某些原因,它不起作用。我正在实现一个watchuser函数,当给定一个参数时,watch就是一个用户(args[1])。但是,当给出“off”的第二个参数(args[2])时,应将该用户从链表中删除,并且不再监视该用户 struct userList * goList; goList = userInventory; do{ if (strcmp(userInventory->username, args[1]) == 0){

我一直在为我正在创建的shell编写这段代码,但由于某些原因,它不起作用。我正在实现一个watchuser函数,当给定一个参数时,watch就是一个用户(args[1])。但是,当给出“off”的第二个参数(args[2])时,应将该用户从链表中删除,并且不再监视该用户

struct userList * goList;
goList = userInventory;
do{
    if (strcmp(userInventory->username, args[1]) == 0){              
       printf("%s\n", args[1]);
       printf("%s\n",userInventory->username);                      
       struct userList * temp2;
       temp2 = userInventory->next;
       if (userInventory->next != NULL){
          userInventory->next = temp2->next;
          userInventory->next->prev = userInventory;
       }                        
       free(temp2);
    }
    goList = goList->next;      
}while  (goList != userInventory);
我的全局结构也如下所示:

struct userList{
    char * username;
    struct userList * prev;
    struct userList * next;
}
因此,此代码不会从我的链接列表中删除用户节点。添加工作,但这个删除功能不会,我不知道为什么。print语句只是为了确保它正在执行它所执行的条件

如果有人能帮我找到错误背后的原因,我将不胜感激。在那之前,我会试着调试这个


谢谢

如果我了解你的代码

问题1(似乎合理):

这是循环列表吗?如果不是,则
while()
中的条件将不会变为真

问题2:

goList = userInventory;
do {
    if (strcmp(userInventory->username, args[1]) == 0) {
    ...
    }
    goList = goList->next;
} while (goList != userInventory);
在这里,您将继续比较列表头部(或尾部)的字符串,而不是比较当前节点中的字符串,
goList
。如果匹配位于
userInventory
最初指向的第一个节点(head/tail),则只能在上述代码中成功查找匹配

问题3:

   temp2 = userInventory->next;
   if (userInventory->next != NULL) {
      userInventory->next = temp2->next;
      userInventory->next->prev = userInventory;
   }
   free(temp2);
让我们假设
userInventory
已更正为
goList

   temp2 = goList->next;
   if (goList->next != NULL) {
      goList->next = temp2->next;
      goList->next->prev = goList;
   }
   free(temp2);
首先,它将
free()
不是匹配的节点,而是它后面的节点(甚至可能
NULL
),这是错误的

其次,这段代码没有对节点进行适当的取消链接和重新链接。应该是什么(假设列表不是循环的):

问题4:

do {
    if (strcmp(goList->username, args[1]) == 0) {
        temp2 = goList;
        if (goList->next != NULL) {
            goList->next->prev = goList->prev; // now goList->next node points to goList->prev node
        }
        if (goList->prev != NULL) {
            goList->prev->next = goList->next; // now goList->prev node points to goList->next node
        }
        free(temp2);
    }
    goList = goList->next;
} while (...);
如果删除成功,此行将访问刚刚释放的节点并可能使程序崩溃:

    goList = goList->next;
因此,您需要将代码更改为:

do {
    if (strcmp(goList->username, args[1]) == 0) {
        temp2 = goList;
        if (goList->next != NULL) {
            goList->next->prev = goList->prev; // now goList->next node points to goList->prev node
        }
        if (goList->prev != NULL) {
            goList->prev->next = goList->next; // now goList->prev node points to goList->next node
        }
        goList = goList->next;
        free(temp2);
    }
    else
    {
        goList = goList->next;
    }
} while (...);
问题5:

goList = userInventory;
如果删除列表头(或是尾部?)节点,则需要更新
userInventory
以指向它后面的下一个节点。否则,您将失去对列表的所有访问权限,因为
userInventory
将指向已释放的内存,而不是剩余的节点(如果有)

问题6(似乎合理):

上面的行没有
free()
内存
temp2->username
。如果它是
malloc()
ed,您希望
free()
it

您应该一步一个脚印地解决问题(例如,首先迭代列表,然后取消链接/重新链接节点,然后删除节点)


当事情不清楚或不起作用时,用纸和铅笔(或画板、钢笔或粉笔)自己想象问题。绘制对象、描绘指针的箭头或它们之间的其他连接等,在对象旁边涂鸦变量名称,以便清楚地看到如何从图表到代码的过程。

您能给出一个最简单的完整示例吗?您的意思是什么?比如你到底在寻找什么?我指的是我们可以复制、粘贴、编译和运行的代码,它将演示错误,并且尽可能短和简单,并且仍然满足这些要求。我建议你使用调试器逐行检查代码,检查所有变量、成员、字符串和指针。那么问题就很明显了。这个列表应该是一个戒指吗?我仔细阅读了代码,确实找到了您在这里讨论的大多数问题。我的代码现在可以工作了,我已经筋疲力尽了。谢谢你的帮助。我非常感激,我会接受你的建议,在我实际构建它之前,先画一个链表。不管怎样,它仍然不起作用。它不是一个循环链表,它是一个双链表。我尝试将do-while循环变成while循环,其中条件为(goList!=NULL),但这不起作用。你会建议把高尔夫球手全部除掉,改用userInventory(我的主列表)吗?如果你继续推进
userInventory
,你需要恢复它。为什么要麻烦?只需使用高尔夫球手。把问题分成几个小问题。画一个子问题。编码。调试它。继续下一个。
do {
    if (strcmp(goList->username, args[1]) == 0) {
        temp2 = goList;
        if (goList->next != NULL) {
            goList->next->prev = goList->prev; // now goList->next node points to goList->prev node
        }
        if (goList->prev != NULL) {
            goList->prev->next = goList->next; // now goList->prev node points to goList->next node
        }
        goList = goList->next;
        free(temp2);
    }
    else
    {
        goList = goList->next;
    }
} while (...);
goList = userInventory;
        free(temp2);