Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/apache/8.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 - Fatal编程技术网

C 问题:从链接列表中删除节点

C 问题:从链接列表中删除节点,c,C,由于代码很神秘,我决定重新编写它 这段代码试图从链表中删除第二个元素(“int data”中编号为2的节点)。remove_节点的第一个参数是列表的第一个指针的地址,因此,如果必须删除列表的第一个指针,则可以从下一个指针开始列表 问题是在第二个while循环中,在if子句中,更具体地说是在free(previous->next)函数中,它正在更改由address_of_ptr(又名*address_of_ptr)指向的地址,我不明白为什么会发生这种情况。有人能启发我吗 #include <

由于代码很神秘,我决定重新编写它

这段代码试图从链表中删除第二个元素(“int data”中编号为2的节点)。remove_节点的第一个参数是列表的第一个指针的地址,因此,如果必须删除列表的第一个指针,则可以从下一个指针开始列表

问题是在第二个while循环中,在if子句中,更具体地说是在free(previous->next)函数中,它正在更改由address_of_ptr(又名*address_of_ptr)指向的地址,我不明白为什么会发生这种情况。有人能启发我吗

#include <stdlib.h>

typedef struct node
{
  struct node *next;
  int data;
} node;

void remove_node(node **address_of_ptr, int int_to_remove)
{
  node *previous;

  while (*address_of_ptr != NULL && (*address_of_ptr)->data == int_to_remove)
  {
    previous = *address_of_ptr;
    *address_of_ptr = (*address_of_ptr)->next;
    free(previous);
  }
  previous = *address_of_ptr;
  address_of_ptr = &((*address_of_ptr)->next);
  while (*address_of_ptr != NULL)
  {
    if ((*address_of_ptr)->data == int_to_remove)
    {
        address_of_ptr = &((*address_of_ptr)->next);
        free(previous->next);
        previous->next = *address_of_ptr;
        /*or
        previous->next = (*address_of_pointer)->next;
        free(*address_of_pointer); 
        address_of_pointer = &previous->next;
        */
    }
    else
    {
        previous = *address_of_ptr;
        address_of_ptr = &((*address_of_ptr)->next);
    }
  }
}

int main(void)
{
  node *head = malloc(sizeof(node));
  node *a = malloc(sizeof(node));
  node *b = malloc(sizeof(node));
  head->next = a;
  a->next = b;
  b->next = NULL;

  head->data = 1;
  a->data = 2;
  b->data = 1;

  remove_node(&head, 2);

  return 0;
}
#包括
类型定义结构节点
{
结构节点*下一步;
int数据;
}节点;
无效删除节点(节点**ptr的地址,int-int-to-u-remove)
{
节点*先前;
while(*address_of_ptr!=NULL&&(*address_of_ptr)->data==int_to_remove)
{
previous=*地址为\u ptr的\u;
*地址\u of \u ptr=(*地址\u of \u ptr)->下一步;
免费(以前);
}
previous=*地址为\u ptr的\u;
地址\u of \u ptr=&(*地址\u of \u ptr)->下一步);
while(*address_of_ptr!=NULL)
{
if((*address\u of\u ptr)->data==int\u to\u remove)
{
地址\u of \u ptr=&(*地址\u of \u ptr)->下一步);
免费(上一个->下一个);
上一个->下一个=*地址\u的\u ptr;
/*或
上一步->下一步=(*指针的地址)->下一步;
自由(*指针的地址);
地址\u指针的\u=&previous->next;
*/
}
其他的
{
previous=*地址为\u ptr的\u;
地址\u of \u ptr=&(*地址\u of \u ptr)->下一步);
}
}
}
内部主(空)
{
node*head=malloc(sizeof(node));
node*a=malloc(sizeof(node));
node*b=malloc(sizeof(node));
head->next=a;
a->next=b;
b->next=NULL;
头部->数据=1;
a->data=2;
b->data=1;
移除_节点(和头部,2);
返回0;
}
我通过pythontutor.com找到了答案

下面是将要用列表中下一个指针的地址替换\u ptr的地址的执行的图像:

#include <stdlib.h>
#include <stdio.h>

typedef struct s_list
{
        struct s_list *next;
        void *data;
} t_list;

void ft_list_remove_if(t_list **begin_list, void *data_ref, int (*cmp)())
{
        t_list *previous;
    t_list *current;

        if (begin_list == 0)
                return;
        while (*begin_list != 0 && (*cmp)((*begin_list)->data, data_ref) == 0)
        {
                previous = *begin_list;
                *begin_list = (*begin_list)->next;
                free(previous);
        }
    current = *begin_list;
        while (current != 0)
        {
                if ((*cmp)(current->data, data_ref) == 0)
                {
                        previous->next = current->next;
                        free(current);
                        current = previous->next;
                }
                else
                {
                        previous = current;
                        current = current->next;
                }
        }
}

int ft_strcmp(char *s1, char *s2)
{
        int i;

        i = 0;
        while (s1[i] == s2[i] && s1[i] != '\0')
                ++i;
        return (s1[i] - s2[i]);
}

int main(void)
{
        t_list *list1 = malloc(sizeof(*list1));
        t_list *list2 = malloc(sizeof(*list2));
        t_list *list3 = malloc(sizeof(*list3));

        list1->data = "a";
        list2->data = "b";
        list3->data = "a";
        list1->next = list2;
        list2->next = list3;
        list3->next = 0;
        ft_list_remove_if(&list1, "b", &ft_strcmp);
        return (0);
}

在我看来,ptr的地址将从head移到a:

但实际情况是:

这也是下一个节点的地址(如a)

在if条款中:

我所期待的是它被设置为b:


由于它与previous->next等价,因此它首先会使程序释放\u ptr的地址。\u

address\u of_ptr=&(*address\u of_ptr)->next)

由于延迟
NULL
指针,将导致未定义的行为。但是,函数
main
提供的示例输入不会出现这种情况,因此这不是问题的原因


您的问题如下:

当第一次在第二个
while
循环的
if
块内执行时(将在第二个
while
循环的第一次迭代中使用示例输入),
address\u of_ptr
将指向链接列表中第一个节点的
下一个
成员,因此指针的值为
&head->next
。这是因为你有线路

address\u of_ptr=&(*address\u of_ptr)->next)

在程序中的多个位置,当您输入
if
块时,它将恰好执行其中一行

if
块的第一行也是该行

address\u of_ptr=&(*address\u of_ptr)->next)

这样,在执行该行之后,
address\u of_ptr
将指向链接列表中第二个节点的
next
成员,因此指针的值将为
&a->next

此时,
previous
的值将是
head
,因为此时

previous=*ptr的地址

执行时,\u ptr的
地址\u的值为
&head

因此,下一行何时开始

免费(上一个->下一个)

执行时,
previous->next
的值将为
a
,这将结束该节点的生存期。如前所述,此时,ptr的
地址\u
将具有值
&a->next
,这意味着ptr的
地址\u现在是一个悬空指针,因为它现在指向一个释放的内存位置。因此,在
free
语句之后,\u ptr
*地址\u发生变化也就不足为奇了,因为释放的内存可以随时变化


请注意,可以以更简单的方式实现函数
remove\u node

void remove_node( node **pp_head, int int_to_remove )
{
    node **pp = pp_head, *p;

    //process one node per loop iteration
    while ( (p = *pp) != NULL )
    {
        //check if node should be removed
        if ( p->data == int_to_remove )
        {
            //unlink the node from the linked list
            *pp = p->next;

            //free the unlinked node
            free( p );
        }
        else
        {
            //go to next node in the list
            pp = &p->next;
        }
    }
}
这一行:

begin_list = &previous->next;
您可能错误地思考了指向指针的指针是如何工作的。由于
begin\u list
是一个
t\u list**
,因此您通常希望分配给
*begin\u list
。另外,由于
previous->next
已经是一个地址,因此您不希望将地址分配给
*begin_list
,而只分配值,因此应该改为:

*begin_list = previous->next;

下面类似的一行也是一样。

在你最初提出这个问题几分钟后,我昨晚准备了一个答案,并且花了很多心思,但直到现在才回来。我会放弃我的版本,但无论如何,这是一个更详细的问题研究,所以我想我应该把它留给后代


问题出在第36行:

                        begin_list = &(*begin_list)->next;
在函数
ft\u list\u remove\u if
的第一个
while
循环中,我可以看到您想要更改列表的开头,以指向列表中可能稍后的某个列表项;因此,例如,如果要删除列表中包含字符串
“a”
的所有项目,此函数确实应该更改
main
函数中
list1
的值;这样,列表的新开始w
                if ((*cmp)((*begin_list)->data, data_ref) == 0)
                {
                        [...]
                }
                else
                {
                        previous = *begin_list;
                        begin_list = &(*begin_list)->next;
                }
                if ((*cmp)((*begin_list)->data, data_ref) == 0)
                {
                        previous->next = (*begin_list)->next;
                        free(*begin_list);
                        begin_list = &previous->next;
                }
                        previous = *begin_list;
                        begin_list = &(*begin_list)->next;
                        to_remove = *begin_list;
                        previous->next = (*begin_list)->next;
                        free(to_remove);
                        begin_list = &previous->next;
#include <stdlib.h>
#include <stdio.h>

typedef struct s_list
{
        struct s_list *next;
        void *data;
} t_list;

void ft_list_remove_if(t_list **begin_list, void *data_ref, int (*cmp)())
{
        t_list *previous;
    t_list *current;

        if (begin_list == 0)
                return;
        while (*begin_list != 0 && (*cmp)((*begin_list)->data, data_ref) == 0)
        {
                previous = *begin_list;
                *begin_list = (*begin_list)->next;
                free(previous);
        }
    current = *begin_list;
        while (current != 0)
        {
                if ((*cmp)(current->data, data_ref) == 0)
                {
                        previous->next = current->next;
                        free(current);
                        current = previous->next;
                }
                else
                {
                        previous = current;
                        current = current->next;
                }
        }
}

int ft_strcmp(char *s1, char *s2)
{
        int i;

        i = 0;
        while (s1[i] == s2[i] && s1[i] != '\0')
                ++i;
        return (s1[i] - s2[i]);
}

int main(void)
{
        t_list *list1 = malloc(sizeof(*list1));
        t_list *list2 = malloc(sizeof(*list2));
        t_list *list3 = malloc(sizeof(*list3));

        list1->data = "a";
        list2->data = "b";
        list3->data = "a";
        list1->next = list2;
        list2->next = list3;
        list3->next = 0;
        ft_list_remove_if(&list1, "b", &ft_strcmp);
        return (0);
}
void remove_node(node **address_of_ptr, int int_to_remove)
{
  node *to_remove;

  while (*address_of_ptr != NULL)
  {
    if ((*address_of_ptr)->data == int_to_remove)
    {
        to_remove = *address_of_ptr;
        *address_of_ptr = (*address_of_ptr)->next;
        free(to_remove);
    }
    else
    {
        address_of_ptr = &(*address_of_ptr)->next;
    }
  }
}