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