c - Valgrind 错误和每个元素一个分配的通用列表

标签 c memory-management valgrind generic-programming pointer-arithmetic

我正在试验链表并尝试创建一个通用的双向链表,它只为每个节点分配一次内存。这意味着节点和节点包含的元素的内存是在同一个 malloc 调用中分配的。 列表本身是一个包含单位大小的结构(使用 sizeof(struct which_is_an_element) 初始化:

struct doubly_linked_list
{
    struct dll_node *head, *tail;
    size_t elem_size;
};

节点:

struct dll_node
{
    struct dll_node *next, *prev;
    void *elem;
};

现在,当我尝试插入元素并对其进行初始化时:

static struct dll_node * new_node(
        struct doubly_linked_list *l, 
        void *elem)
{
    struct dll_node *n = malloc (
        sizeof(struct dll_node) + l->elem_size);

    // This line throws valgrind error
    memcpy(n + sizeof(struct dll_node), elem, l->elem_size); 

    n->prev = n->next = NULL;
    n->elem = n + sizeof(struct dll_node);
    return n;
}

我收到一个 valgrind 错误:

Invalid write of size 8
at 0x4C3217B: memcpy@@GLIBC_2.14 (vg_replace_strmem.c:1022) by 0x400705: new_node (doubly_linked_list.c:20)
by 0x400768: dl_list_insert_at_tail (doubly_linked_list.c:30)
by 0x40093F: main (main.c:24)
Address 0x5204280 is 480 bytes inside an unallocated block of size 4,194,112 in arena "client"

  1. 当分配内存的大小等于sizeof(struct which_is_an_element) + sizeof(dll_node)时,真的memcpy写入未分配 block 吗?
  2. 这些问题是否是由 valgrind 认为分配的内存大小为 sizeof(struct dll_node) 引起的,因为 new_node< 中名为 n 的指针类型 指向数据的函数?
  3. 这种方法好吗?我可以为每个元素分配一次内存,还是应该分别为节点和元素分配内存?
  4. 如果这种方法很好,那么我怎样才能摆脱这个 valgrind 错误?

最佳答案

Does really memcpy write inside unallocated block as the size of the allocated memory is equal to sizeof(struct which_is_an_element) + sizeof(dll_node)?

是的。

执行 memcpy(n + sizeof(struct dll_node), ...sizeof(struct dll_node) * sizeof *n(等于 sizeof(struct dll_node) * sizeof(struct dll_node)) 超出 n 指向的字节数。

您可能只想“寻找”sizeof(struct dll_node) 个字节。

这样做,将您的代码更改为:

memcpy((char*)n + sizeof(struct dll_node), ...

或者,因为n指向struct dll_node的指针,就这样

memcpy(n + 1, ...

超越 struct dll_node

关于c - Valgrind 错误和每个元素一个分配的通用列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48150621/

相关文章:

c - 从字符串中删除扩展名和目录?

c - C 中的字符串动态分配

c - 如何编写递归 Strrchr?

cocoa-touch - 有时保留循环可以吗?

c - valgrind : Conditional jump or move depends on uninitialised value using strlen() strncat()

c - C 编译器优化局部静态变量是否合法?

swift - Deinit 方法从未被调用 - Swift Playground

android - 退出Activity后如何释放实际的Activity对象内存?

c - 段错误和使用 Valgrind 进行调试

有条件的跳跃或移动取决于未初始化的值