2016-06-30 12 views
1

Ich habe versucht, eine einfach verlinkte Liste in c zu implementieren. Ich wollte in der Lage sein, mehrere Instanzen der Liste zu verwenden, und ich wollte die Liste in der Hauptfunktion erstellen. Deshalb habe ich beschlossen, es so zu implementieren, wie ich es getan habe.C malloc valgrind - nicht initialisierter Speicher in meiner Implementierung der einfach verknüpften Liste

Der Code funktioniert einwandfrei gut, aber ich bin besorgt wegen der Ausgabe Valgrind erstellt. Auch habe ich versucht, den Code in einem Projekt auf einem eingebetteten System zu verwenden und seltsame Fehler passieren.

valgrind Die Ausgabe ist:

gestartet ...

== == 3570 Bedingter Sprung oder bewegen, hängt von uninitialised Wert (e)

== == 3570 bei 0x100000E8E : push_cfront (in ./map_test)

== == 3570 durch 0x100000D4F: main (in ./map_test)

== == 3570 Uninitialised Wert wurde durch eine Heapzuordnung erstellt

== == 3570 bei 0x100008EBB: malloc (in /usr/local/Cellar/valgrind/3.11.0/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)

== == 3570 durch 0x100000E80: push_cfront (in ./map_test)

== == 3570 durch 0x100000D4F: main (in ./map_test)

== == 3570

. ..finish

Auch es sagt mir, dass ich einen Block verliere. Wo mache ich einen Fehler zu befreien es

== == 3570 LEAK ZUSAMMENFASSUNG:

== == 3570 definitiv verloren: 16 Bytes in 1 Blöcke

== 3570 == indirekt verloren : 0 0 Bytes in Blöcken

== == 3570 möglicherweise verloren: 2.064 Bytes in Blöcken 1

== == 3570 noch erreichbar: 0 0 Bytes in Blöcken

== == 3570 unterdrückt: 24.525 Bytes in 186 Blöcke

Bitte geben Sie mir einen Hinweis auf, wo ich schief gelaufen ist.

test.c:

#include <stdio.h> 
#include <stdint.h> 
#include <stdlib.h> 
#include "command_list.h"  
int main() { 

    printf("starting...\n"); 

    Clist * command_list = malloc(sizeof(Clist)); 
    if (command_list == NULL) printf("Malloc Failed\n"); 
    command_list->head = NULL; 

    //push_cback(command_list, 0); 
    push_cfront(command_list,1); 

    free_clist(command_list); 
    free(command_list); 
    printf("\n...finished\n"); 
    return 0; 
} 

command_list.h:

#ifndef __COMMAND_LIST_H 
#define __COMMAND_LIST_H 

typedef struct cnode { 
    uint8_t command; 
    struct cnode * next; 
} Cnode; 

typedef struct clist { 
    Cnode * head; 
} Clist; 

void push_cback(Clist * list, uint8_t command); 
void push_cfront(Clist * list, uint8_t command); 
void free_clist(Clist * list); 

#endif 

command_list.c

void push_cfront(Clist * list, uint8_t command){ 
    Cnode * new_node; 
    new_node = malloc(sizeof(Cnode)); 
    if (new_node->next == NULL) { 
     return; 
    } 
    new_node->command = command; 
    new_node->next = list->head; 
    list->head = new_node; 
} 

void free_clist(Clist * list){ 
    if (list->head == NULL){ 
     return; //already empty 
    } 
    Cnode * current = list->head; 
    while (current->next != NULL){ 
     Cnode* temp = current->next; 
     free(current); 
     current = temp; 
    } 
    free(current); 
    list->head = NULL; 
} 
+3

In der dritten Zeile von '' push_cfront Sie tun 'if (new_node-> nächste == NULL)' Sie nur 'das Ding malloc'ed; 'next' ist nicht gesetzt. Ziemlich sicher, dass Sie 'if (new_node == NULL)' verwenden wollten. – WhozCraig

+1

Oh, und Requisiten für die Verwendung von Valgrind. – WhozCraig

+0

Ich denke, du solltest nach 'list == NULL' suchen, nur für den Fall :) – niceman

Antwort

0

Sie haben ein paar Probleme. Sie überprüfen new_node->next (nicht initialisierte Daten im Malloc'd-Speicher) anstelle von new_node (der Rückgabewert von malloc). Auf meinem Computer bewirkt dies zumindest auch, dass der Speicher nicht freigegeben wird, da new_node->next zufällig null ist, also kehren Sie ohne Freigabe zurück new_node. Wenn Sie außerdem das Zurückschieben einer verknüpften Liste unterstützen möchten, sollten Sie eine zirkulär verknüpfte Liste in Betracht ziehen, da diese Operation ermöglicht wird, ohne dass die gesamte Sache durchlaufen werden muss.

Schließlich ein paar Tipps: Es ist gut, dass Sie Valgrind verwenden, aber es wird hilfreicher sein, wenn Sie mit -g Debugging-Symbole zu aktivieren, damit Valgrind Ihnen Zeilennummern sagen. Auch wenn ich verknüpfte Listen mache, verwende ich gerne einen Dummy-Kopfknoten für einige Operationen, um einen speziellen Fall für leere oder Singleton-Listen zu vermeiden. Zum Einsetzen in eine sortierte Liste verknüpft, sieht diese Technik wie:

int sorted_insert(Clist *list, char new_command){ 
    Cnode _head = {NULL, list->head}, *head = &_head, *prev = head, *tmp;//head is an auto dummy node obviating null checks. 
    int ord = -1;//If there are no existing nodes, newObj would be less than all objects. 
    while(prev->next && (ord = (int)newObj - prev->next->command)) > 0){//Iterate by prev->next not curr to use only one pointer. 
     prev = prev->next;//Looping while there is a next node and its data compares less than new_command. 
    } 
    if((!ord) || !(tmp = malloc(sizeof(Cnode))){//newObj is already in the list or allocation failed. 
     return 0; 
    } 
    *tmp = (Cnode){.next=prev->next, .command=new_command}; 
    prev->next = tmp; 
    list->head = head->next;//un- add head which is then deallocated by stack frame cleanup. 
    return 1; 
} 
+0

Danke löschen. Das machte es deutlicher, warum ich manchmal ein paar Blöcke verlor und manchmal nicht. Eigentlich habe ich das Programm mit -g kompiliert und auch valgrind mit diesem Befehl benutzt. Valgrind --leak-check = full --track-origins = yes – lugges

0

Die new_node->next nicht initialisiert ist, wenn Sie es Wert überprüfen. Du brauchst das nicht.

Wenn Sie nach malloc Fehlern suchen, legen Sie einen Rückgabecode für die Funktion fest und überprüfen Sie sie beim Aufruf.

Bis dahin wird der if-Zweig in push_cfront nicht benötigt.

... oder wollten Sie stattdessen list->head überprüfen?

0

Auch ist es ein Problem mit diesem Stück Code in push_cfront

new_node = malloc(sizeof(Cnode)); 
if (new_node->next == NULL) { 
    return; 
} 

Es ist nicht definiertes Verhalten, da new_node Speicher nicht initialisiert wird. Sie wollten wahrscheinlich überprüfen if (new_node == NULL), um zu sehen, ob Speicher tatsächlich zugewiesen wurde.

+0

Ok danke an alle, die auf das Problem mit der Überprüfung von new_node-> next hingewiesen haben. Ich sehe das Problem nicht mit meiner kostenlosen Methode. Ich habe den verbleibenden Knoten nach der while-Schleife freigegeben. Eigentlich glaube ich, dass Sie versuchen, null in Ihrer free_clist() Methode freizugeben. Oder liege ich falsch? – lugges

+0

@Lugges oh, du hast Recht. Verpasst frei (aktuell), werde mehr in das schauen, ich werde den Teil über free_clist für jetzt aus der Antwort – buld0zzr