细分错误/列表初始化

时间:2018-11-23 04:46:46

标签: c

我想创建一个具有以下结构的列表:

  • list.h:包含函数原型并定义数据类型
  • lt.c:测试列表的主要功能
  • list.c:列表的实际实现

执行它时,我总是会遇到段错误。尝试使用gdb识别它时,表明这是lt.c中以下行的错误:

list_t *li=list_init();

我的lt.c文件的其余部分如下所示:

#include <stdio.h>
#include <stdlib.h>
#include "list.h"

int main ( int argc, char *argv [ ], char *envp [ ] )
{
    list_t *li=list_init();
//li=list_init();
   /* if((li=list_init())==NULL)
    {
        perror (" Cannot allocate memory" ) ;
        exit(-1);
    }*/
}

我对list.c函数list_init()的实现如下:

list_t *list_init ()
{
    list_t* newlist = malloc(sizeof(*newlist));
if (!newlist)
{
    perror ("malloc-newlist");
    exit (EXIT_FAILURE);
}`enter code here`
   //newlist->first=NULL;
    //newlist->last=NULL;
newlist->first = (struct list_elem *) malloc(sizeof(struct list_elem));
newlist->last  = (struct list_elem *) malloc(sizeof(struct list_elem));
    return newlist;
}

我的list.h文件如下:

    struct list_elem {
    struct list_elem *next; // Zeiger auf das naechste Element
    char         *data; // Zeiger auf ein Datenobject
};

typedef struct list {
    struct list_elem *first;// erstes Element in der Liste
    struct list_elem *last; // letztes Element in der Liste
} list_t;

/* function prototypes */
list_t           *list_init ();

但是,我不知道如何更改实现,以使其不再发生。 非常感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

虽然无法准确判断问题出在哪里,但我怀疑问题出在两个地方之一。首先,您正在使用字符串文字初始化每个data成员,该字符串在除少数系统以外的所有系统上都是只读的。因此,如果您尝试在代码中的任何地方尝试修改data,则可能会遇到SegFault。如果您以后尝试free (pointer->data);

,同样适用

二,您无法正确分配node->next指针,从而导致遍历尝试取消引用导致同一SegFault的NULL指针或 indeterminate 指针。如果您的append函数无法正确处理if (!list->first) { ... }情况或需要设置else

pointer->next = newnode;情况,就会发生这种情况

除非发布了enter image description here,否则实际上没有办法告诉您,但是鉴于列表操作有些通用,您可以使用与init()和{{1 }}函数(添加了append()print()函数以很好地衡量),例如

free()

使用/输出示例

#include <stdio.h>
#include <stdlib.h>

struct list_elem {
    struct list_elem *next;     // Zeiger auf das naechste Element
    char *data;                 // Zeiger auf ein Datenobject
};

typedef struct list {
    struct list_elem *first;// erstes Element in der Liste
    struct list_elem *last; // letztes Element in der Liste
} list_t;

/* function prototypes */
list_t *list_init ();
struct list_elem *list_append (list_t *list, char *data);
void list_print (list_t *list);
void list_free (list_t *list);

int main (void)
{
    list_t *li = list_init();

    if (list_append (li, (char[]){"erstes"}) == NULL || 
        list_append (li, (char[]){"zweites"}) == NULL ||
        list_append (li, (char[]){"drittes"}) == NULL) {
        perror ("Cannot allocate memory" ) ;
        exit (EXIT_FAILURE);
    }

    list_print (li);
    list_free (li);

    exit (EXIT_SUCCESS);
}

list_t *list_init (void)
{
    list_t *newlist = malloc (sizeof *newlist);

    if (!newlist) {
        perror ("malloc-newlist");
        exit (EXIT_FAILURE);
    }

    newlist->first = NULL;
    newlist->last = NULL;

    return newlist;
}

struct list_elem *list_append (list_t *list, char *data)
{
    struct list_elem *node = NULL;

    if (!list)
        return NULL;

    if (!(node = malloc (sizeof *node))) {
        perror ("malloc-node");
        return NULL;
    }
    node->data = data;
    node->next = NULL;

    if (!list->first)
        list->first = node;
    else {
        struct list_elem *iter = list->first;
        while (iter->next)
            iter = iter->next;
        iter->next = node;
    }

    return (list->last = node);
}

void list_print (list_t *list)
{
    struct list_elem *iter = NULL;

    if (!list)
        return;

    iter = list->first;

    while (iter) {
        printf ("%s\n", iter->data);
        iter = iter->next;
    }
}

void list_free (list_t *list)
{
    struct list_elem *iter = NULL;

    if (!list)
        return;

    iter = list->first;

    while (iter) {
        struct list_elem *victim = iter;
        iter = iter->next;
        free (victim);
    }

    free (list);
}

内存使用/错误检查

无需强制返回$ ./bin/ll_list_elem erstes zweites drittes ,这是不必要的。参见:A Minimal, Complete, and Verifiable Example (MCVE)

在您编写的任何动态分配内存的代码中,对于任何分配的内存块,您都有2个职责:(1)始终保留指向起始地址的指针因此,(2)当不再需要它时可以释放

当务之急是使用一个内存错误检查程序来确保您不会尝试访问内存或在已分配的块的边界之外/之外进行写入,不要试图以未初始化的值读取或基于条件跳转,最后,以确认您释放了已分配的所有内存。

对于Linux,malloc是正常选择。每个平台都有类似的内存检查器。它们都很容易使用,只需通过它运行程序即可。

valgrind

始终确认已释放已分配的所有内存,并且没有内存错误。

$ valgrind ./bin/ll_list_elem ==22383== Memcheck, a memory error detector ==22383== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. ==22383== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info ==22383== Command: ./bin/ll_list_elem ==22383== erstes zweites drittes ==22383== ==22383== HEAP SUMMARY: ==22383== in use at exit: 0 bytes in 0 blocks ==22383== total heap usage: 4 allocs, 4 frees, 64 bytes allocated ==22383== ==22383== All heap blocks were freed -- no leaks are possible ==22383== ==22383== For counts of detected and suppressed errors, rerun with: -v ==22383== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) 指针与正向链接一起使用

由于您有一个last指针,因此不需要列表的泛型迭代即可找到最后一个指针。我怀疑您打算使用正向链接。在这种情况下,您只需修改last,如下所示:

append()

注意 if (!list->first) list->first = node; else list->last->next = node; 的分配在list->last = node中进行处理)

答案 1 :(得分:0)

我认为您没有以适当的方式分配内存。

TList *list_init()
{
   TList *newList = (TList *) malloc(sizeof(TList));

   newList->first = (struct list_elem *) malloc(sizeof(structlist_elem));
   newList->last  = (struct list_elem *) malloc(sizeof(struct list_elem));

newList->first->next= NULL;
newList->last->next= NULL;

return newList;
}