C - segfault中的免费通用链表

时间:2016-10-02 23:02:14

标签: c linked-list segmentation-fault free generic-programming

我正在用C编写一个通用链表(在 Kyle Loudon 的书之后), 但是当谈到免费它时,我得到了一个段错误

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

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;
}

由函数指针传递的Destroy:

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;
}

segfault由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\0"));
chrPtr = "uno\0";
list_ins_next(&myList,NULL,chrPtr);

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

chrPtr = NULL;
iptr = NULL;

getchar();

list_destroy(&myList);

1 个答案:

答案 0 :(得分:1)

main()的代码中,您有:

chrPtr = malloc(sizeof("uno\0"));
chrPtr = "uno\0";
  1. 当C自动添加一个时,为什么显式\0
  2. 你能说'内存泄漏'吗?你分配内存;通过将字符串文字的地址分配给同一个指针,立即覆盖指向该分配内存的唯一指针。
  3. strcpy()发生了什么?
  4. 由于这种滥用行为,您将未分配的内存指针传递给free();实际上,您将指向字符串常量的指针传递给free()。这是未定义的行为,很容易导致崩溃!

    问题不在于您最初显示的代码中;它在其他代码中。这也是为什么MCVE(Minimal, Complete, Verifiable Example) - 又名{SSCCE Short, Self-Contained, Correct ExamplementionedGreg 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()中的代码非常不通用。支持代码可以处理它 - 但异构列表很棘手;不要尝试它,直到你没有遇到这种问题。一个整数列表;精细。一个字符串列表;精细。一个整数和字符串列表 - 狡猾!