Zeiger auf Verzweiflung



  • Das hast du vollkommen richtig erkannt. Ist von meinem Prof und da ich heute in der Vorlesung nicht anwesend war (wegen Krankheit - nicht Faulheit ;)) bin jetzt dran den Kram nachzuarbeiten.

    Aufgabe ist es Werte über eine Schleife auf dem Speicher abzulegen (bzw. auch zu entfernen) und um da eine Kontrolle zu haben, ob ich auf dem richtig Weg bin, habe ich die Fktn aufgerufen.



  • Dann zeige doch mal die ganze Aufgabe und den Code, der zur Verfügung gestellt wurde.



  • Hallo, hier die vorgegebenen Funktionen:

    List* List::push(int i) {
        return new List(i, this);
    }
    
    List* List::pop() {
        if (next == 0) return this;
        List tmp = *this;
        delete this;
        return tmp.next;
    }
    
    void List::print(int get) { //<- meine gedachte Lösung (wahrscheinlich absolut falsch)
        cout << "Adresse (Push): " << push(get)  << " | Wert: " << item << endl;
    }
    

    Der Header soll wie folgt aussehen:

    class List { 
    public:
        List() : item(0), next(0) {
        }
    
        List(int i, SiLL* p) : item(i), next(p) {
        }
        List* push(int i);
        List* pop();
        void print(int get); //<- das habe ich mir überlegt
    
    private:
        int item;
        List* next;
    };
    

    Aufgabenstellung dazu:
    1. Schnittstelle der Klasse erweitern, um eine Methode zur Ausgabe eines kompletten List-Objekts zu ermöglichen.
    2. In einer Schleife int Werte auf den Stapel anlegen und anschließend entfernen.

    Wie eine verkettete Liste "funktioniert" ist mir klar. Man hat verschiedene Einträge auf dem Speicher, die jeweils einen "Wert" und eine Adresse besitzen. Über die Adresse wird der jeweils folgende (bei doppelt verketteten Listen auch der vorherige) Eintrag erreichbar. Auch, dass ein Zeiger nicht unbestimmt sein darf ist mir bekannt.
    Bei mir scheitert es wahrscheinlich am Verständnis für die Implementierung...
    Ich würde einfach gerne sehen wie ich zB drei Einträge korrekt eingebe.

    Nochmals vielen Dank für eure Hilfe.
    Martin


  • Mod

    Dann erklär doch mal, wieso eine Funktion, die eine komplette Liste ausgeben soll, einen int-Parameter braucht. Was macht der?



  • Ich hätte die Funktion in der main aufgerufen und jeweils den int übergeben, den ich ablegen wollte. Allerdings entsteht da wahrscheinlich auch ein Fehler (eher ein Problem), da ja die Funktion push() im cout aufgerufen werden würde.
    Ist es hier besser einen Zeiger zu übergeben?
    Mir fällt es schwer da überhaupt eine Herangehensweise zu finden. 😞



  • martini3k1 schrieb:

    Ich würde einfach gerne sehen wie ich zB drei Einträge korrekt eingebe.

    Dreimal Push aufrufen. Rückgabe ist jeweils das letzte Element, welches intern auf den vorgänger zeigt. Du nimmst also immer das Rückgabeobjekt welches Push liefert und rufst darauf wiederum die Funtkion auf.

    martini3k1 schrieb:

    Aufgabenstellung dazu:
    1. Schnittstelle der Klasse erweitern, um eine Methode zur Ausgabe eines kompletten List-Objekts zu ermöglichen.

    Ausgabe! Nur Ausgabe machen, sonst nichts. Ist also der falsche Ansatz die Liste mittels Push in der Print-Funktion zu erweitern. Du fängst beim letzten Element an und hangelst Dich in einer Schleife von einem zum nächsten via next-Zeiger. Für jedes Element gibst Du einfach den Wert (item) aus.

    martini3k1 schrieb:

    2. In einer Schleife int Werte auf den Stapel anlegen und anschließend entfernen.

    So wie ganz oben die 3 Elemente von Hand gepusht, jetzt aber in einer Schleife. Immer den Rückgabewert merken und diesen in der nächsten Iteration wieder pushen.
    Und entfernen? Gleiches Spiel, nur mit Pop



  • Okay, das hilft mir schon mal auf die Sprünge. Allerdings muss ich doch noch irgendwo einen konstanten (Start-)Zeiger anlegen um zu wissen wo ich anfange, oder?

    Hangelt man sich so

    int value = next->item;
    

    durch die Einträge?

    Hat irgendjemand einen Ratschlag oder Kniff, wie man an Zeiger "sinnvoll" rangeht?
    Sinnvoll ist vielleicht nicht der richtige Ausdruck - ich meine damit Folgendes:
    Wenn ich sonst ein Problem habe, greife ich gerne mal auf den Debugger zurück und schaue mir an was das Programm überhaupt macht. Sobald ich mit Zeigern anfange ist das nicht mehr möglich, da meist nichts vollständig kompiliert wird.



  • Ja so in etwa. Wenn du etwas das erste Mal in die Liste hinzufügst, hast du deine Startposition.



  • Gut, allerdings erzeuge ich ja in der main das Objekt. Somit müsste ich doch in der main auch den Zeiger auf den ersten Eintrag erhalten und diesen dann an die print-Funktion übergeben, um von dort aus "weiterlaufen" zu können. Aber auch das will nicht klappen.
    Ihr macht mit mir schon was mit.^^



  • martini3k1 schrieb:

    Aber auch das will nicht klappen.

    zeig doch mal deinen Versuch.

    martini3k1 schrieb:

    Ihr macht mit mir schon was mit.^^

    och, da hatten wir schon Schlimmere 😉



  • Das beruhigt mich, dass ich nicht der Einzige bin, der sich damit schwer tut (fürs erste Semester finde ich das schon recht heftig).

    So habe ich mir das vorgestellt:
    List.cpp:

    void List::print(int* pPos) {
    
        item = pPos->next;
    
        cout << "Adresse (Push): " << " " << " | Wert: " << item << endl;
    }
    

    main:

    List* object = new List;
    
        int* pPos = &object;
    
        object->push(4);
        object->print(pPos);
    


  • Du solltest dir dringend nochmal die Grundlagen von Objektorientierung ansehen...

    warum meinst du, print() ein Argument übergeben zu müssen?



  • Hier, damit Du was zum erweitern hast. Denk daran Dich am Ende auch um das aufräumen zu kümmern (zu jedem new gehört ein delete).
    Jetzt schaffst Du aber den Rest oder?

    class List {
    public:
        List() : item(0), next(0) {
        }
        List(int i, List* p) : item(i), next(p) {
        }
        List* push(int i);
        List* pop();
    
        void print();
    
    private:
        int item;
        List* next;
    };
    
    void List::print()
    {
        cout<<item<<"\n";
        if(next != NULL)
            next->print();
    }
    
    List* List::push(int i) {
        return new List(i, this);
    }
    
    List* List::pop() {
        if (next == NULL) return this;
        List tmp = *this;
        delete this;
        return tmp.next;
    }
    
    int main()
    {
        List* next = new List(1, NULL);
        next = next->push(2);
        next = next->push(3);
        next = next->push(4);
    
        next->print();
    }
    


  • Danke! Ich glaube jetzt habe ich es verstanden. Dass ich für eine print-Funktion nichts übergeben muss, war mir schon klar. Die Funktion hat ja Zugriff auf die Klassenvariablen.
    Allerdings wäre ich komischerweise nicht auf "objekt = objekt->push(..)" gekommen. Ich weiß auch nicht warum, wahrscheinlich sah ich vor lauter Zeigern keinen Zusammenhang mehr.
    Nochmals 1000-Dank an alle! 🙂



  • Hallo,

    ich möchte euch noch mal was zu den doppelt verketten Listen fragen:

    Meine bisherigen Überlegungen:
    -Pointer für vorhergehenden (prev) und nächsten (next) Eintrag anlegen
    -beim ersten Eintrag ("head") muss der Pointer auf "prev(ious)" auf NULL zeigen
    -beim letzten Eintrag ("tail") bei "next" ebenfalls.

    Wenn ich nun bei dem ersten Eintrag anfange, prüfe ich ob this = 0 ist, wenn ja wird der int-Wert, this und NULL zurückgegeben, da ja kein vorhergehender Eintrag vorhanden ist.
    Beim zweiten Eintrag sieht die Sache bereits anders aus, da ich dort die Speicheradresse vom ersten Eintrag ebenfalls ablegen muss. Demnach müsste der int-Wert, this und prev zurückgegeben werden.

    Allerdings komme ich mal wieder auf keinen grünen Zweig was die Bestimmung von der vorherigen Speicheradresse angeht.
    Wäre die Realisierung möglich, indem man einen temporären Zeiger sichert, der dann dort eingefügt wird?


  • Mod

    Wenn ein Programm den Wert von etwas später nochmal braucht, dann bietet sich dafür eine Variable an, ja.



  • Und nochmal Hallo. 🙂

    Ich komme so langsam auf den richtigen Dampfer.
    Bin jetzt dabei eine doppelt verkettete Liste zu erstellen.

    Die Auswertung der Speicheradressen funktioniert schon recht gut, allerdings gibt es Probleme mit dem Verlassen der Schleifen.
    Wenn ich das Programm debuggen will, stürzt es ab. Wenn ich es hingegen ausführe werden die Speicheradressen korrekt angezeigt, nur halt in einer Schleife, die ca. 10x so oft durchläuft als sie eigentlich sollte.
    An was kann das liegen? Und wenn mir jemand sagen (bzw. überprüfen) kann, ob meine push-Fktn so in dieser Form richtig ist, wäre ich sehr dankbar.
    Irgendwas mache ich noch falsch, bzw. fehlt mir noch an Wissen. Wie gesagt, ich bin über jeden Ratschlag froh. 🙂

    Hier mein Code:

    void DoLL::start() { // Vorheriges Nullsetzen des Einstiegspunkts
        top = tail = NULL;
    }
    
    void DoLL::push(int v) {
    
    //    DoLLNode* dummy1;
    //    DoLLNode* dummy2;
    
        if (top == NULL) {  // Prüfe, ob das erste Element erstellt wird
            top = node;
            tail = node;
            node = new DoLLNode(v, NULL, this->node);       // PREV auf NULL
        } else {            // Prüfe, ob das letzte Element erstellt wird
            if (!node->next) {
                node->prev = tail;
                node->next = NULL;
                tail = node;
                node = new DoLLNode(v, node->prev, NULL); // NEXT auf NULL
            } else {        // "Normales" befüllen der Liste
                node->prev = tail;
                tail->next = node;
                tail = node;
                node = new DoLLNode(v, node->prev, node->next);
            }
        }
    }
    
    void DoLL::print() {
        cout << node->item << " | akt. Adresse: " << this->node << " | next->" << node->next << " | prev->" << node->prev << "\n";
        if (node != NULL) {
            node = node->next;
            print();
        }
    }
    

    Und der Aufruf in der main-Fktn

    DoLL* object = new DoLL();
    
        object->start();    //top und tail = NULL
    
        for (int i = 0; i < 10; i++) {
            object->push(i);
        }
        cout << "Aktuelle INT-Werte auf dem Speicher: " << endl;
        object->print();
    

    Besten Dank vorab!
    Martin


Anmelden zum Antworten