C 中的免费通用链表 - 段错误

Free generic linked list in C - segfault

我正在用 C 编写通用链表(根据 Kyle Loudon 的书), 但是当谈到释放它时,我遇到了 segfault.

用于列表定义的数据类型:

typedef struct list_elem_
{
    void                *data;
    struct list_elem_   *next;
} list_elem;

typedef struct link_list_
{
    int         size;
    int         (*match)(const void *key1, const void *key2);
    void            (*destroy)(void *data);
    list_elem       *head;
    list_elem       *tail;
} link_list;

用于销毁调用者数据的函数:

void destroy_data(void *data)
{
    if(data)
        free(data);

    return;
}

通过函数指针销毁:

void list_init(link_list *list, void (*destroy)(void *data))
{
    list->size = 0;
    list->destroy = destroy;
    list->head = NULL;
    list->tail = NULL;

    return;
}

释放列表:

void list_destroy(link_list *list)
{
    void* data;

    while(list_size(list) > 0)
        if(list_rem_next(list, NULL, (void**)&data) == 0 && list->destroy != NULL)
            list->destroy(data);

    memset(list,0,sizeof(link_list));

    return;
}

段错误是由destroy_data中的free触发的。

==============编辑====================

删除列表元素

int list_rem_next(link_list *list, list_elem *element, void **data)
{
    list_elem *OldElement;

    if(list_size(list) ==0)
        return -1;

    /* Remove the head */
    if(element == NULL)
    {
        *data = list->head->data;
        OldElement = list->head;
        list->head = list->head->next;

        if(list_size(list) == 1)
            list->tail = NULL;

    /* Remove other than head */
    } else {
        if(element->next == NULL)
            return -1;

        *data = element->data;
        OldElement = element->next;
        element->next = element->next->next;

        if(element->next == NULL)
            list->tail = element;
    }

    free(OldElement);

    list->size--;

    return 0;
}

=================== 编辑 2 ======================== ==

在主要内部

link_list   myList;
int i;
int *iptr;
char *chrPtr;

list_init(&myList, destroy_data);

for(i = 0; i < 4; i++)
{
    iptr = malloc(sizeof(int));
    *iptr = i;
    list_ins_next(&myList, NULL, iptr);
}

chrPtr = malloc(sizeof("uno[=15=]"));
chrPtr = "uno[=15=]";
list_ins_next(&myList,NULL,chrPtr);

chrPtr = malloc(sizeof("stringa numero due[=15=]"));
chrPtr = "stringa numero due[=15=]";
list_ins_next(&myList,NULL,chrPtr);

chrPtr = NULL;
iptr = NULL;

getchar();

list_destroy(&myList);

在来自 main() 的代码中,您有:

chrPtr = malloc(sizeof("uno[=10=]"));
chrPtr = "uno[=10=]";
  1. 为什么 C 自动在其后加一时显式 [=14=]
  2. 你能说'memory leak'吗?你分配内存;您通过将字符串文字的地址分配给同一指针来立即覆盖指向该分配内存的唯一指针。
  3. strcpy() 怎么了?

由于这种滥用,您将未分配的内存指针传递给 free();事实上,您正在将指向字符串常量的指针传递给 free()。这是未定义的行为,很容易导致崩溃!

问题不在您最初显示的代码中;它在其他代码中。这也是 MCVE (Minimal, Complete, Verifiable Example) — aka SSCCE (Short, Self-Contained, Correct Example) by Greg Hewgill — 如此重要的原因。我们没有办法调试您未显示的代码 — 而且确定问题不在您显示的代码中是不必要的艰苦工作。

您可能会使用:

chrPtr = strdup("uno"));
list_ins_next(&myList, NULL, chrPtr);

chrPtr = strdup("stringa numero due");
list_ins_next(&myList,NULL,chrPtr);

避免麻烦。如果做不到这一点,您可以使用:

chrPtr = malloc(sizeof("uno"));
strcpy(chrPtr, "uno");
list_ins_next(&myList, NULL, chrPtr);

chrPtr = malloc(sizeof("stringa numero due"));
strcpy(chrPtr, "stringa numero due");
list_ins_next(&myList,NULL,chrPtr);

这些都没有检查内存分配是否成功;这也应该在生产代码中完成,并且可以说在学校作业中完成。

注意sizeof("string literal")算空字节,所以长度是正确的。同样注意 strlen("string literal") 不计算空字节——小心!

代码中可能还有其他问题;我还没有证实一切都是干净的。但是这部分会更干净,也更有可能正常工作。


函数 list_size()list_ins_next() 未显示。大小可猜; list_ins_next() 没那么容易。

我还观察到代码将 4 个整数和 2 个字符串插入到列表中。没有办法知道那是事后插入的内容。 main() 中的代码非常不通用。支持代码可以处理它——但是异构列表很棘手;在您不 运行 遇到此类问题之前不要尝试。一个整数列表;美好的。一个字符串列表;美好的。一个整数和字符串列表 - 狡猾!