C语言 SEGV:将节点添加到链表末尾时大小为 8 的 invalig 写入



我有这个函数:

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_tnode_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.因为tmp0,所以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是列表的初始节点。

通常,为指针创建这样的别名是一个坏主意。它使理解您的代码变得困难。

此外,如果要将节点附加到单向链表

的末尾,则应声明一个双侧单向链表。对于单侧单向链表,此函数效率低下。

相关内容

  • 没有找到相关文章