如何在c中删除链表中的节点

如何在c中删除链表中的节点,c,linked-list,C,Linked List,我需要做的是在c中实现一个函数来删除链表中的一个节点,使用strcmp的for和while循环。程序编译得很好,但循环从未停止过,有什么建议可以改进吗 结构如下: struct Test { char name[16]; int id; }; typedef struct Node { struct Test structure; struct Node * next; }TNode; typedef TNode * Nodo; 我写的函数是: void Delete(Nodo

我需要做的是在c中实现一个函数来删除链表中的一个节点,使用strcmp的for和while循环。程序编译得很好,但循环从未停止过,有什么建议可以改进吗

结构如下:

struct Test
{
 char name[16];
 int id;
};

typedef struct Node
{
 struct Test  structure;
 struct Node * next;
}TNode;

typedef TNode * Nodo;
我写的函数是:

void Delete(Nodo * pp)
 {
  Nodo i;
  char temp[16], name[16];

  printf("Insert the name to delete:");
      scanf(" %s", name);

for(i = *pp; i->next != NULL ; i = i->next)
  {
    if(strcmp(i->structure.name, name) == 0)
      {
        while(i->next != NULL)
        {
          strcpy(temp,i->structure.name);
          strcpy(i->structure.name, i->next->structure.name);
          strcpy(i->next->structure.name, temp);
          i = i->next;
         }
      }
   }
 }
更新:工作功能如下,感谢一些程序员的解释:

void Delete(Nodo * pp)
{
  Nodo i, prev;
  char name[16];

  printf("Insert the name to delete:");
     scanf(" %s", name);

//case for the first node

  if(strcmp((*pp)->structure.name, name) == 0)
  {
    Nodo old = *pp;
    *pp = (*pp)->next;
    free(old);
    return;
  }

//loop to delete node inside list

  for(prev = *pp, i = prev->next; i != NULL ; prev = i, i = i->next)
  {
    if(strcmp(i->structure.name, name) == 0)
      {
        prev->next = i->next;
        free(i);

        break;
      }
  }
}
[注意:这实际上并没有回答这个问题,但它告诉我们如何在单个链接列表中取消节点链接,IMO是OP面临的最大问题。]

假设您有以下列表

+---+ +---+ +---+ +---+ | A | -> | B | -> | c | -> | D | +---+ +---+ +---+ +---+ 这是不对的

相反,您使
A
节点的
next
指针指向
C
,因此现在列表变为

+---+ +---+ +---+ +---+ | A | -\ | B | /-> | c | -> | D | +---+ | +---+ | +---+ +---+ \-------/
取消节点链接的技巧是跟踪上一个节点。它可以这样实现:

// Special case: Removing the first node in the list
if (strcmp((*pp)->structure.name, name) == 0)
{
    TNode *old = *pp;  // Save a pointer to the node that should be removed

    *pp = (*pp)->next;  // Actually unlink the node from the list

    free(old);  // Free the memory of the old node

    return;
}

TNode *prev;  // To keep track of previous node
TNode *curr;  // The "current" node

for (prev = *pp, curr = prev->next; curr != NULL; prev = curr, curr = curr->next)
{
    if (strcmp(curr->structure.name, name) == 0)
    {
        // Found the node to remove
        prev->next = curr->next;  // Unlink the current node from the list

        free(curr);  // Free the node

        break;  // No need to iterate anymore
    }
}
通过将
prev
初始化为
NULL
,并改为使用
*pp
启动
curr
,可以在循环内部解决第一个被删除节点的“特殊情况”。然后,您需要检查
prev
是否为
NULL
,或者是否不在循环中的
if

代码看起来可能更多,可能有更多的行(即使删除了部分或全部空行),但我认为大多数人会说这更容易理解和了解发生了什么


当然,您还需要添加一个空列表检查,
pp
本身不为null(比如
pp!=null&&*pp!=null
)。

最好的做法是不要在typedef中隐藏指针。例如,您让我陷入了创建的混乱中…请注意,您的函数无法处理空列表,或仅包含一个节点的列表。如果复制后,我释放了最后一个节点,该怎么办?它将变成A-C-D-D,而不是A-C-D,如果我想删除,比如说C,首先列表将变成A-B-D-D,我释放最后一个节点,它将变成A-B-D。请告诉我这个推理是否有效。@St3veR0nix是的,它有效,但这比仅仅更改一个指针要复杂得多。而且可能会让许多程序员在看你的代码时感到困惑,因为在处理列表时更改指针是一种常见的方法。顺便说一句,我仍然很难找到答案,你能用一些代码回答吗? +---+ +---+ +---+ | A | -> | c | -> | D | +---+ +---+ +---+
// Special case: Removing the first node in the list
if (strcmp((*pp)->structure.name, name) == 0)
{
    TNode *old = *pp;  // Save a pointer to the node that should be removed

    *pp = (*pp)->next;  // Actually unlink the node from the list

    free(old);  // Free the memory of the old node

    return;
}

TNode *prev;  // To keep track of previous node
TNode *curr;  // The "current" node

for (prev = *pp, curr = prev->next; curr != NULL; prev = curr, curr = curr->next)
{
    if (strcmp(curr->structure.name, name) == 0)
    {
        // Found the node to remove
        prev->next = curr->next;  // Unlink the current node from the list

        free(curr);  // Free the node

        break;  // No need to iterate anymore
    }
}