2016-12-03 9 views
1

Ich schreibe ein bisschen C-Code und versuche, ein bisschen mit Listen zu spielen. Aus irgendeinem Grund bringt der folgende Code mir den Autor, Jahr und ISBN des Buches, aber der Titel fehlt. Ich vermute, dass es irgendwo in der Funktion "insert_at_begin" ein Speicherleck gibt. Obwohl ich mir wirklich nicht sicher bin, was ich dort machen soll. Das Programm liest aus einer Datei mit Buchnamen, Autoren usw. und sollte diese als dynamische Liste zurückgeben.Speicherverlust in einer C-verknüpften Liste

Jeder Hinweis oder irgendeine Art von Hilfe würde sehr geschätzt werden. Ich habe mich im Internet umgesehen und einen Stack-Überlauf gefunden, konnte aber keine Lösung für dieses Speicherleck finden. Ich habe den entsprechenden Code hinzugefügt, obwohl es ziemlich lang ist, ich bin mir nicht sicher, wo das Leck ist, also dachte ich, es wäre besser so.

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

Dies ist, was gedruckt wird, wie Sie die Titel sehen können fehlen und einige der Informationen wird immer abgehackt. Ich habe das X-Code-Leaks-Tool versucht, konnte dort aber nichts Nützliches finden. Ich habe eine printf-Funktion zum Debuggen in der while-Schleife von read_list hinzugefügt, und dort funktionierte es perfekt. Also muss es etwas mit der insert_at_begin Funktion sein.

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

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

UPDATE: Hier ist die read_line Funktion:

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

Verwenden Sie [Valgrind] (http://valgrind.org/). Ihre Schleife innerhalb von 'free_list' sollte wahrscheinlich 'while (ptr)' durchlaufen und sollte mit 'nextptr = ptr-> next enden; frei (ptr); ptr = nextptr; '. Und Sie sollten eine Zeichnung auf Papier oder Karton machen, um die Form Ihrer Datenstrukturen zu verstehen. –

+0

Zeige Teil von 'read_line' – BLUEPIXY

+0

Zeigen Sie uns den Platz, wo Sie den Speicher für die Strings' title' und 'author' reservieren. Ihre Datenstruktur enthält nur Zeiger auf sie - sie müssen auf einen Speicherbereich zeigen, der für die gesamte Lebensdauer der Datenstruktur gültig ist. – tofro

Antwort

1

Es mir sieht aus, als wenn Sie keine Speicher author und title zugeordnet wurden.

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

besser funktionieren würde, aber würden Sie Titel/Autor Charakter zu 100 ...

so sollten Sie wirklich verwenden malloc oder calloc zuzuteilen den Speicher benötigen Sie zählen beschränken - Ich schlage vor, den Code oben, nur um holen Sie sich die Sache auf eine schnelle und schmutzige Basis arbeiten ...

+0

hinzugefügt Aber ich kann ihnen nicht Werte innerhalb der Funktion construct_element zuweisen richtig? – BoazKG

+1

Ja, der Code müsste anderswo geändert werden ... Ich denke, hier sind zwei Punkte relevant (1) 'element * book = malloc (sizeof (element));' räumt zur Zeit keinen Platz für die Zeichen-Arrays (Strings) und (2) wenn Sie Werte aus der Datei importieren und lesen, legen Sie sie nicht an einem Ort ab, an dem Speicher zugewiesen wurde. - Sie müssen irgendwo Speicher für 'title' und' author' reservieren - ich würde nur vorschlagen, dass Sie anfangen sollten, indem Sie es in Ihre Strukturdefinition einfügen - dann müssten Sie wahrscheinlich '' Funktionen wie 'strcpy verwenden 'um Zeichenfolgen zu verschieben (char arrays) – tom

+0

Danke! Ich habe eine feste Größe für den Titel und den Autor in der Strukturdefinition und im construct_element den folgenden Code hinzugefügt: 'strcat (Buch-> Titel, Titel); strcat (Buch-> Autor, Autor); 'Jetzt wird alles korrekt angezeigt. Mache ich das richtig? – BoazKG

1

Wenn Sie einen Hinweis zu fragen, also werde ich Ihnen keine vollständige Lösung geben: ist

Das Problem, das Sie mit auf Ihre zwei Zeichen im Zusammenhang Felder in Ihrem struct, Titel und Autor. Sie sind Zeiger, keine Variablen fester Größe. Das bedeutet, dass Sie Speicherplatz für sie reservieren müssen. Sie müssen sich jeweils für eine geeignete Größe entscheiden, den Speicherplatz für sie zuweisen und dann den Text aus der Datei in den zugewiesenen Speicherplatz kopieren. Im Moment vergeben Sie nur Platz für die Zeiger auf die Zeichenfelder.

+0

Das bedeutet, dass die Zuordnung erfolgen muss, bevor ich ihnen Werte mit der read_file-Funktion richtig zuweisen? – BoazKG

+0

Wenn Sie in construct_element Speicher für das Element reserviert haben, weisen Sie auch Speicher für die Zeichenfolgen zu, die Sie speichern möchten. Sie können dies als eine allgemeine Regel betrachten: Wenn eine Struktur Felder hat, die keine feste Größe haben, müssen Sie Speicher für die Struktur und für jedes dieser dynamischen Felder reservieren. – codemonkey65

+0

Danke, es hat funktioniert. – BoazKG