我有这个函数:
int list_add_elem_at_back(list_t *front_ptr, double elem)
{
list_t item = malloc(sizeof(list_t));
list_t tmp = *front_ptr;
if (item == NULL)
return (0);
item->value = elem;
item->next = NULL;
while (tmp != NULL)
tmp = tmp->next;
tmp->next = item;
return (1);
}
它应该在列表的后面添加一个节点,从 t_list *front_ptr
开始。
仅供参考:list_t
是node_t *
的别名。
执行它时,我收到SegV崩溃,Valgrind日志如下:
==3814== Invalid write of size 8
==3814== at 0x4006C1: list_add_elem_at_back (simple_list.c:63)
==3814== by 0x400A83: populate_list (simple_list.c:181)
==3814== by 0x400B5C: main (simple_list.c:202)
==3814== Address 0x521f048 is 0 bytes after a block of size 8 alloc'd
==3814== at 0x4C2FB6B: malloc (vg_replace_malloc.c:299)
==3814== by 0x40067D: list_add_elem_at_back (simple_list.c:56)
==3814== by 0x400A83: populate_list (simple_list.c:181)
==3814== by 0x400B5C: main (simple_list.c:202)
==3814==
==3814== Invalid write of size 8
==3814== at 0x4006EF: list_add_elem_at_back (simple_list.c:66)
==3814== by 0x400A83: populate_list (simple_list.c:181)
==3814== by 0x400B5C: main (simple_list.c:202)
==3814== Address 0x8 is not stack'd, malloc'd or (recently) free'd
第 63 行和第 66 行是item->next = NULL;
和tmp->next = item;
,这让我认为它来自我为"下一个"节点分配(或没有?(内存的方式,但我无法找出问题所在。
任何帮助,不胜感激。
您正在分配sizeof(list_t)
,这是一个指针。您必须执行以下操作:
malloc(sizeof(node_t));
正是这个隐藏*
的糟糕想法的结果.
第二个问题:当head
NULL
时,您将一个空指针传递给带有 &head
的函数。显然next
处于偏移0x08
.因为tmp
是0
,所以tmp->next
0 + 0x08
。可以使用head = malloc(sizeof(node_t))
进行快速检查。
正如其他人所说,将node_t *
混淆为list_t
是一个非常糟糕的主意。
您的第一个错误是:
list_t item = malloc(sizeof(list_t));
相当于
node_t *item = malloc(sizeof(node_t *));
您分配的是指针的大小,而不是node_t
实例的大小。
你应该有
node_t *item = malloc(sizeof(node_t));
您的第二个错误来自您浏览列表的方式。
list_t tmp = *front_ptr;
while (tmp != NULL)
tmp = tmp->next;
tmp->next = item;
当 tmp 为 NULL 时,你的 while 循环停止,这意味着下一行 (tmp->next = item;
( NULL->next = item;
,这当然是无效的。
此外,如果 *front_ptr 为 NULL(例如,当您尝试创建第一个元素时(,它会跳过循环(这是正常的(,并生成相同的问题。
以下是我会做的:
int list_add_elem_at_back(node_t **front_ptr, double elem)
{
node_t *item = malloc(sizeof(node_t));
node_t *tmp;
if (item == NULL) {
return (0);
}
item->value = elem;
item->next = NULL;
if (*front_ptr == NULL) {
*front_ptr = item;
} else {
tmp = *front_ptr;
while (tmp->next != NULL)
tmp = tmp->next;
tmp->next = item;
}
return (1);
}
以下代码片段
int add_node(list_t *front_ptr, double elem)
{
list_t item = malloc(sizeof(list_t));
^^^^^^^^^^^^^ ^^^^^^
没有意义,因为分配了一个指针而不是类型为 node_t
的结构。
我想你的意思是
int list_add_elem_at_back(list_t *front_ptr, double elem)
{
list_t item = malloc(sizeof(*list_t));
int success = item != NULL;
if ( success )
{
item->value = elem;
item->next = NULL;
while ( *front_ptr != NULL) front_ptr = &( *front_ptr )->next;
*front_ptr = item;
}
return success;
}
并且该函数可以通过以下方式调用
list_add_elem_at_back( &head, value );
其中head
是列表的初始节点。
通常,为指针创建这样的别名是一个坏主意。它使理解您的代码变得困难。
此外,如果要将节点附加到单向链表的末尾,则应声明一个双侧单向链表。对于单侧单向链表,此函数效率低下。