无法从链接列表中删除节点

时间:2012-10-23 04:03:59

标签: c linked-list

我一直在研究我正在创建的shell的代码,但由于某种原因它无法正常工作。我正在实现一个watchuser函数,在给出参数时监视用户(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 个答案:

答案 0 :(得分:1)

如果我了解您的代码,

问题1(看似合理):

goList = userInventory;
do {
    ...
    goList = goList->next;
} while (goList != userInventory);

这是一份循环清单吗?如果不是,那么while ()中的条件就不会成真。

问题2:

goList = userInventory;
do {
    if (strcmp(userInventory->username, args[1]) == 0) {
    ...
    }
    goList = goList->next;
} while (goList != userInventory);

在这里,您不断比较列表头部(或尾部)中的字符串,而不是比较当前节点goList中的字符串。如果匹配位于userInventory最初指向的第一个节点(头/尾),则查找匹配只能在上面的代码中成功。

问题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),这是错误的。

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

   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);

问题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);

以上行不free() temp2->username后面的内存。如果是free(),您需要malloc()

你应该一步一步地解决问题(例如,首先,遍历列表,然后取消链接/重新链接节点,然后删除节点)。

当事情不清楚或不起作用时,请使用纸和铅笔(或绘图板和笔或粉笔)为自己想象问题。绘制对象,描绘指针的箭头或它们之间的一些其他连接等,在对象旁边涂写变量名称,这样您就可以清楚地看到如何从图表进展到代码。