Einfach verkettete Liste
-
Hallo!
Versuche eine einfach verkettete Liste mit folgender Struktur zu schreiben:
typedef struct user { char *name; char *comment; int id; struct user *next; } user_ts;
Bekomme aber einen Speicherzugriffsfehler in der Funktion add_user. Habe die Stelle mit dem Fehler ausfindig machen können, weiß aber nicht was daran falsch ist. Den Zeiger auf den ersten User (head) habe ich global deklariert (also vor die main-Funktion geschrieben. Hier die Funktion, die den Fehler verursacht:
user_ts *add_user(char *name, char *comm, int id) { user_ts *new_user = NULL; user_ts *current_user = first_user; /* first_user ist global ! */ if (first_user == NULL) { new_user = first_user; } new_user = (user_ts *)malloc(sizeof(user_ts)); if (new_user == NULL) { return (NULL); } new_user->name = (char *)malloc(strlen(name) * sizeof(char)); new_user->comment = (char *)malloc(strlen(comment) * sizeof(char)); if (new_user->name == NULL || new_user->comment == NULL) { return (NULL); } strcpy(new_user->name, name); strcpy(new_user->comment, comment); new_user->id = id; new_user->next = NULL; /* Hier liegt wohl der Fehler */ /* -------------------------------*/ if (new_user != first_user) { while(current_user->next != NULL) { current_user = current_user->next; } current_user->next = new_user; } /* -------------------------------*/ return (new_user); }
Was mache ich falsch?
Gruß
Michael
-
ist first_user vielleicht 0?
-
Hallo!
'first_user' habe ich wie folgt deklariert:
. . . user_ts *first_user = NULL; int main () { . . .
Gruß
Michael
-
Jo, da liegt das Problem.
Beim ersten Aufruf von add_user ist first_user NULL und somit weisst du current_user NULL zu. Und current_user->next fliegt dir um die Ohren.
-
Hallo!
Das kann doch eigentlich nicht sein, da durch
if (new_user != first_user) { ... }
sichergestellt ist, dass current_user nur dann aufgerufen wird, wenn first_user != NULL ist. Also first_user schon einen user hat.
Das Problem habe ich mitlerweile doch lösen können. Es liegt, wenn ich recht überlege, an einen Fehler, den ich schon so häufig gemacht habe. Stichwort: Call by value. Eine Funktion legt von allen Parametern und deklarierten Variablen Kopien an. Somit wird durch [/cpp]
if (first_user == NULL)
{
new_user = first_user;
}
[cpp]
new_user zwar die Adresse von first_user zugeordnet und Speicher reserviert. Nach verlassen der Funktion sind aber alle Variablen, die in der Funktion deklariert wurden, weg. Somit ist auch new_user weg und first_user ist weiterhin NULL.
Bitte verbessert mich, wenn ich falsch liegeGruß
Michael
-
Kann sein, dass ich gerade irgendetwas nicht so ganz überblicke, aber was willst Du mit dem folgenden Code erreichen?
if (first_user == NULL) { new_user = first_user; }
Du überprüfst doch, ob first_user NULL ist, d.h. first_user zeigt nirgendwo hin. Trotzdem willst Du dann first_user an new_user zuweisen. Warum? Davon abgesehen wird new_user doch in der folgenden Zeile so oder so ein neuer Speicherbereich zugewiesen, d.h. die Zuweisung hat am Ende gar keinen Effekt.
Kann es sein, dass Du was anderes beabsichtigt hast?
Das fiel mir nur gerade so auf...
Edit: Und noch was:
if (new_user != first_user) { ... }
Ich glaube, hier beabsichtigst Du Deiner Erklärung nach auch was anderes als Du geschrieben hast. Beim ersten Mal ist first_user NULL und damit überprüst Du ob new_user != NULL ist, was natürlich zutrifft. Somit wird der Code innerhalb der Klammern augeführt und - wie Shade bereits sagte - current_user->next schiesst Dein Programm ab.
-
Hallo!
Meine Idee war, wenn beim ersten Durchlauf first_user == NULL ist und durch
if (first_user == NULL) { new_user = first_user; }
new_user die Adresse von first_user bekommt, ist new_user == first_user.
Somit werden für den Rest des Codes alle Operationen auf first_user ausgeführt. Undif (new_user != first_user) { ... }
nur dann ausgeführt wird, wenn bereits der erste Eintrag für first_user vorhanden ist.
Gruß
Michael
-
Zeiger sind ja im Prinzip - wie Du wahrscheinlich weisst - Variablen, die eine Speicheradresse aufnehmen. Bei der Zuweisung new_user = first_user weist Du folglich den Inhalt von first_user - NULL - an new_user zu. Mehr passiert bei diesem Stück Code nicht. Wie bereits vorher erwähnt, wird diese Zuweisung durch die darauf folgende Zeile ohnehin unwirksam, weil Du dort new_user einen neuen Wert zuweist. Um sicherzustellen, dass new_user und first_user auf das selbe Objekt zeigen, musst Du first_user die Adresse des neu erstellten Objekts, die in new_user steht, zuweisen. Das muss nach der Zeile new_user = (user_ts *)malloc(sizeof(user_ts)); passieren.
Wenn Du Deine Funktion wie folgt änderst, sollte sie eigentlich funktionierenuser_ts *add_user(char *name, char *comm, int id) { user_ts *new_user = NULL; user_ts *current_user = first_user; /* first_user ist global ! */ new_user = (user_ts *)malloc(sizeof(user_ts)); if (new_user == NULL) { return (NULL); } if (first_user == NULL) //hier ist die Aenderung { first_user = new_user; } [...] return(new_user); }