0

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

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

出于某种原因,此代码不会从我的链接列表中删除用户节点。添加工作,但这个删除功能不会,我不知道为什么。打印语句只是为了确保它正在执行条件,它就是。

如果有人可以帮助我找到错误背后的原因,我将不胜感激。到那时,我将尝试调试它。

谢谢。

4

1 回答 1

0

如果我对您的代码有任何了解,

问题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->usernamefree()如果它是malloc()ed ,你想要它。

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

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

于 2012-10-23T04:57:42.420 回答