Problem mit einer verketteten Liste



  • Hallo Leute,

    ich und meine Semester-Crew, wir haben da ein kleines Problem mit dem untenstehenden Modul. Unser Programm läuft einfach net so, wie wir uns das vorstellen, denn z.b. beim Speichern der Akten bricht das Programm ab mit nem core dump.
    Wir brüten nun schon seit ner woche fast jeden Tag an dem Dingens und bekommens einfach net auf die Reihe... 😡
    Vielleicht hat ja jmd von euch ne idee, wo das Problem liegen könnte.
    Achtung: es geht hier eigentlich nur um eine doppelt verkettete Liste.

    Um jeden Vorschlag sind wir dankbar... 🙄

    Gruss, chefkoch

    PS: Kommentare sind alle vom Prof.

    Hier das Modul:

    // kette.cpp
    
    #include <string>
    #include <cstdlib>
    using namespace std;
    #include "kette.h"
    using namespace chained_list;
    
    // streng geheim
    
    namespace
    {
      // Kettenelement, entspricht einer Akte
      struct Node
      {
        // Aktennummer
        unsigned number;
        // Akteninhalt
        string text;
        // Zeiger auf nächsten rechten Nachbarn
        Node *next;
        //Zeiger auf das vorherige Element der Liste
        Node *prev;
      };
    
      // Zeiger auf Startelement und aktuelles Element
      // Nullzeiger bedeuten nicht vorhandene Kette
      Node *start = 0, *current = 0;
    
      // finde den linken Nachbarn des aktuellen Elementes
      // Eingabe:  --
      // Rückgabe: Zeiger auf linken Nachbarn
    
      Node *findPredecessor(void)
      {
        // Zeiger für die Suche
        //Node *ptr;
        // am linken Ende anfangen
        //ptr = start;
        // solange der rechte Nachbar nicht das aktuelle Element ist
        //while (ptr->next != current)
        //{
          // gehe zum nächst rechten Nachbarn
          //ptr = ptr->next;
        //}
        // Zeiger auf linken Nachbarn zurückgeben
        //return ptr;
    
        return current->prev;
      }
    } // namespace
    
    // streng öffentlich
    
    namespace chained_list
    {
    
      // Konstruktor für verkettete Liste
      // Eingabe:  --
      // Rückgabe: --
    
      void chainDefine(void)
      {
        // gibt es etwa schon eine verkettete Liste???
        if (start != 0)
        {
          // böser Klient
          exit(1);
        }
    
        // Startelement anlegen
        start = new Node;
        // Endelement anlegen
        start->next = new Node;
        // Endelement kennzeichnen
        start->next->next = 0;
    
        //Zeiger auf start
        start->next->prev = start;
    
        // aktuelles Element ist Startelement
        // Kennzeichen für existierende aber leere Kette
        current = start;
      }
    
      // Destruktor für verkettete Liste
      // Eingabe:  --
      // Rückgabe: --
    
      void chainDelete(void)
      {
        // gibt es überhaupt eine Kette???
        if (start == 0)
        {
          // der Klient ist ein Scherzkeks
          exit(1);
        }
    
        // löschen der Elemente von links nach rechts
        current = start;
        // solange es einen rechten Nachbarn gibt
        while (current != 0)
        {
          // gehe dahin
          current = current -> next;
          // lösche das ursprüngliche Element
          delete start;
          // alter rechter Nachbar ist neuer linker Rand
          start = current;
        }
    
        // Kette existiert nicht mehr
        start = current = 0;
      }
    
      // mache linken Nachbarn zum aktuellen Element
      // Eingabe:  --
      // Rückgabe: true, wenn es linken Nachbarn gibt, sonst false
    
      bool moveBack(void)
      {
        // ist linker Nachbar das Endelement?
        if (current->next->prev == 0)
        {
          // ja, aktuelles Element bleibt
          return false;
        }
        // nein, linker Nachbar wird aktuelles Element
        current = current->prev;
        return true;
      }
    
      // mache rechten Nachbarn zum aktuellen Element
      // Eingabe:  --
      // Rückgabe: true, wenn es rechten Nachbarn gibt, sonst false
    
      bool moveForth(void)
      {
        // ist rechter Nachbar das Endelement?
        if (current->next->next == 0)
        {
          // ja, aktuelles Element bleibt
          return false;
        }
        // nein, rechter Nachbar wird aktuelles Element
        current = current->next;
        return true;
      }
    
      // neues Element rechts vom aktuellen einfügen und zum neuen aktuellen Element machen
      // Eingabe:  number - Aktennummer des neuen Elementes
      //           text - dessen Inhalt
      // Rückgabe: --
    
      void insertNode(unsigned number, string text)
      {
        // Zeiger auf neues Element
        Node *ptr;
    
        // neues Element erschaffen
        ptr = new Node;
        // Aktennummer einlesen
        ptr->number = number;
        // Akteninhalt einlesen
        ptr->text = text;
        // rechter Nachbar ist rechter Nachbar vom aktuellen Element
        ptr->next = current->next;
        //linker Nachbar
        current->next = ptr;
    
        //Zeiger auf linke Nachbarn
        ptr->prev = ptr->next->prev;
    
        //Zeiger auf neues Element
        ptr->next->prev = ptr;
    
        // neues ist nun das aktuelle Element
        current = current->next;
      }
    
      // aktuelles Element löschen
      // Eingabe:  --
      // Rückgabe: --
    
      void deleteNode(void)
      {
        // Suchzeiger
        Node *ptr;
    
        // ist Kette leer?
        if (current == start)
        {
          return;
        }
    
        // linken Nachbarn suchen
        ptr = findPredecessor();
        // aktuelles Element ausgliedern
        ptr->next = current->next;
        // aktuelles Element löschen
        delete current;
    
        // linker Nachbar neues aktuelles Element
        current = ptr;
        // es sei denn, linker Nachbar wäre Startelement und Kette nicht leer
        if (current == start && current->next->next != 0)
        {
          // dann doch besser zum rechten Nachbarn des Startelementes
          current = current->next;
        }
      }
    
      // Element auslesen
      // Eingabe:  --
      // Rückgabe: number - Aktennummer des aktuellen Elements
      //           text - dessen Akteninhalt
      //           true, wenn Kette nicht leer ist, sonst false
    
      bool readNode(unsigned &number, string &text)
      {
        // ist Kette leer?
        if (current == start)
        {
          // ja, number und text haben keine sinnvolle Bedeutung
          return false;
        }
    
        // Aktennummer auslesen
        number = current->number;
        // Akteninhalt auslesen
        text = current->text;
        // number und text haben sinnvolle Bedeutung
        return true;
      }
    
      // aktuelles Element ändern
      // Eingabe:  number - neue Aktennummer
      //           text - neuer Akteninhalt
      // Rückgabe: true, wenn es aktuelles Element überhaupt gibt
    
      bool writeNode(unsigned number, string &text)
      {
        // ist Kette leer?
        if (current == start)
        {
          // ja, kein Element geändert
          return false;
        }
    
        // Aktennummer ablegen
        current->number = number;
        // Akteninhalt ablegen
        current->text = text;
        // Erfolg anzeigen
        return true;
      }
    } // namespace data chain
    


  • Hallo,

    //function deleteNode():
        // linken Nachbarn suchen
        ptr = findPredecessor();
        // aktuelles Element ausgliedern
        ptr->next = current->next;
        // aktuelles Element löschen
        delete current;
    
        // linker Nachbar neues aktuelles Element
        current = ptr;
    

    current->next->prev zeigt immernoch auf den freigegebenen Speicherbereich, wenn
    ich das hier richtig sehe. Bevor du current loeschst, muesste imho noch ein
    current->next->prev = ptr; hin.

    mfg
    v R



  • function deleteNode(): 
        // linken Nachbarn suchen 
        ptr = findPredecessor(); 
        // aktuelles Element ausgliedern 
        ptr->next = current->next; 
    
        //also hier rein?
        current->next->prev = ptr;
    
        // aktuelles Element löschen 
        delete current; 
    
        // linker Nachbar neues aktuelles Element 
        current = ptr;
    

    So meinste, ne?
    Gute Idee, aber wenn ich speichern will, also die Akten in eine *.txt reinschreiben will, bekomm ich noch immer ein core dump... 😕

    Greetz



  • Ja so dachte ich und zwar weil, wenn current->next->prev immernoch auf den
    Speicherbereich verweist, welcher freigegeben worden ist und man nun auf
    current->next->prev zugreift, kommt es zu einem segfault.

    Wenn es das nicht war, kommst du ums debuggen nicher herum. Alternativ kannste
    auch mal strace nutzen, falls du unter Linux/*BSD arbeitest.

    mfg
    v R



  • hmm... stimmt, was du meinst...
    Hab das ma verbessert, bekomme aber noch immer ein core dump als segfault, wenn ich speichern will...
    ich benutze cygwin unter win, demnach g++ auf der Konsole.

    werd ma weiter forschen und wenn ichs hab, dann poste ichs hier rein, fals es von Interesse ist...

    Gruss und besten Dank


Anmelden zum Antworten