2016-12-03 5 views
1

Я пишу немного кода C и пытаюсь немного поиграть со списками. По какой-то причине следующий код приносит мне Автору, Год и ISBN книги, но название отсутствует. Я подозреваю, что это утечка памяти где-то в функции «insert_at_begin». Хотя я действительно не уверен, что делать там. Программа читает из файла с именами книг, авторов и т. Д. И возвращает его в виде динамического списка.Утечка памяти в C-связанном списке

Любые подсказки или какая-либо помощь будет принята с благодарностью. Я просмотрел интернет и переполнение стека, но не смог найти решение этой утечки памяти. Я добавил соответствующий код, хотя его довольно долго, я не уверен, где протекает, поэтому я подумал, что это будет лучше.

typedef struct _element element; 


typedef struct _list { 
    element *first;  
    int count;   
} list; 


struct _element { 
    char* title; 
    char* author; 
    int year; 
    long long int isbn; 
    element *next; 
}; 


element *insert_at_begin(element *first, element *new_elem) { 

    if(first) { 
     new_elem->next = first; 
     first = new_elem; 

    } else { 
     first = new_elem; 
    } 

    return first; 

} 


element *construct_element(char *title, char* author, int year, long long int isbn) { 

    element* book = malloc(sizeof(element)); 
    book->title = title; 
    book->author = author; 
    book->year = year; 
    book->isbn = isbn; 
    book->next = NULL; 
    return book; 
} 


void free_list(list *alist) { 

    //Only when there is 2 elements in the list start this loops 
    for (int i=1; i<alist->count; i++) { 
     free(alist->first->next); 
    } 

    free(alist->first); 
    free(alist); 

} 


void read_list(char* filename, list *alist) { 
    element* new_elem; 

    char* title; 
    char* author; 
    int year; 
    long long int isbn; 
    read_line_context ctx; 
    open_file(&ctx, filename); 
    while(read_line(&ctx, &title, &author, &year, &isbn) == 0) { 
     new_elem = construct_element(title, author, year, isbn); 
     alist->first = insert_at_begin(alist->first, new_elem); 
     alist->count++; 
    } 
} 

list* construct_list() { 
    list *alist = malloc(sizeof(list)); 
    alist->first = NULL; 
    alist->count = 0; 
    return alist; 
} 


void print_list(list *alist) { 
    printf("My Books\n================\n\n"); 
    int counter = 1; 
    element *elem = alist->first; 
    while (elem != NULL) { 
     printf("Book %d\n", counter); 
     printf("\tTitel: %s\n", elem->title); 
     printf("\tAuthor: %s\n", elem->author); 
     printf("\tYear: %d\n", elem->year); 
     printf("\tISBN: %lld\n", elem->isbn); 
     elem = elem->next; 
     counter++; 
    } 
} 

int main(int argc, char** argv) { 
    list *alist = construct_list(); 
    read_list(argc>1?argv[1]:"buecherliste.txt", alist); 
    print_list(alist); 
    free_list(alist); 
    return 0; 
} 

Это то, что будет напечатано, как вы можете видеть названия отсутствуют и часть информации становится сколами. Я попробовал инструмент X Code Leaks, но не нашел там ничего полезного. Я добавил функцию printf для отладки в while-loop read_list, и там она отлично работала. Так что это должно быть что-то с функцией insert_at_begin.

My Books 
================ 

Book 1 
    Titel: 
    Author: Phillip K. Dick 
    Year: 1973 
    ISBN: 9780547572178 
Book 2 
    Titel: 
    Author: nner Darkly 
    Year: 1949 
    ISBN: 9783548267456 

UPDATE: Вот функция read_line:

int read_line(read_line_context *ctx, char **name, char **author, int *year, long long int *isbn) { 
    if (ctx->filepointer == NULL){ 
     perror(ctx->filename); 
     exit(1); 
    } 
    char *name_s; 
    char *author_s; 
    char *year_s; 
    char *isbn_s; 
    char *delim = ";"; 
    ssize_t len; 

    if ((len = getline(&(ctx->line), &(ctx->linecapp), ctx->filepointer)) != -1) 
    { 
     /* remove tailing newline */ 
     char *pos; 
     if ((pos = strchr(ctx->line, '\n')) != NULL) 
      *pos = '\0'; 

     /* read individual fields */ 
     name_s = strtok(ctx->line, delim); 
      author_s = strtok(NULL, delim); 
     year_s = strtok(NULL, delim); 
     isbn_s = strtok(NULL, delim); 
     if(name_s != NULL && author_s != NULL && year_s != NULL && isbn_s != NULL) { 
      *name = name_s; 
      *author = author_s; 
      *year = atoi(year_s); 
      *isbn = atoll(isbn_s); 
      return 0; 
     } 

    } 
    fclose(ctx->filepointer); 
    ctx->filepointer = NULL; 
    ctx->linecapp = 0; 
    if (ctx->line != NULL) { 
     free(ctx->line); 
    } 
    return -1; 
} 
+0

Использовать [valgrind] (http://valgrind.org/). Ваша петля внутри 'free_list' должна, вероятно, зацикливаться на' while (ptr) 'и должна заканчиваться на' nextptr = ptr-> next; свободный (PTR); ptr = nextptr; '. И вы должны сделать рисунок на бумаге или доске, чтобы понять форму ваших структур данных. –

+0

Показать часть 'read_line' – BLUEPIXY

+0

Покажите нам место, где вы выделяете память для строк' title' и 'author'. Ваша структура данных содержит только указатели - они должны указывать на некоторую область памяти, которая действительна для всего времени жизни структуры данных. – tofro

ответ

1

Он смотрит на меня, как если бы вы не выделили какой-либо памяти author и title.

struct _element { 
    char title[100]; 
    char author[100]; 
    int year; 
    long long int isbn; 
    element *next; 
}; 

будет работать лучше, но будет ограничивать Считает название/автор персонажу 100 ...

так что вы действительно должны использовать malloc или calloc выделить память вам нужно - я предлагаю код выше только получить вещь работает на быстрой и грязной основе ...

+0

Но тогда я не могу присвоить им значения внутри функции construct_element правильно? – BoazKG

+1

Да, вам нужно изменить код в другом месте ... Я думаю, что здесь есть две точки: (1) 'element * book = malloc (sizeof (element));' в данный момент не выделяет пространство для массивов символов (строк) и (2) при импорте и чтении значений из файла вы не помещаете их в место, где была выделена память. - вам нужно выделить память где-то для 'title' и' author' - я просто предлагаю вам начать с размещения в определении вашей структуры - тогда вам, вероятно, придется использовать '' функции типа 'strcpy 'для перемещения строк (char arrays) – tom

+0

Спасибо! Я добавил фиксированный размер для заголовка и автора в определении структуры, а в contruct_element - следующий код: 'strcat (book-> title, title); strcat (книга-> автор, автор); 'Теперь все проявляется правильно. Правильно ли я это делаю? – BoazKG

1

вы просите подсказку, так что я не дам вам полное решение:

проблема вы испытываете связанную с вашим двумя полукокса полей в вашем struct, название и автор. Это указатели, а не переменные фиксированного размера. Это означает, что вам нужно выделить для них пространство памяти. Вам нужно будет выбрать соответствующий размер для каждого, выделить место для них и затем скопировать текст из файла в выделенное пространство памяти. На данный момент вы выделяете пространство для указателей на поля char.

+0

Это означает, что распределение должно произойти до того, как я присвою им значения с помощью функции read_file? – BoazKG

+0

В build_element, после выделения памяти для элемента, также выделяйте память для символьных строк, которые вы хотите сохранить. Вы можете считать это общим правилом: если в структуре есть поля, которые не имеют фиксированного размера, вам необходимо выделить память для структуры и для каждого из этих динамических полей. – codemonkey65

+0

Спасибо, это сработало. – BoazKG