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 liege 😕

    Gruß
    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. Und

    if (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 funktionieren

    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 ! */
    
    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);
    }
    

Anmelden zum Antworten