#include using namespace std; void zahlEinlesen(void) // eine Möglichkeit Zahlen in umgekehrter Reihenfolge wieder auszugeben { int zahl; // hier wird jeweils eine neue Variable zahl angelegt // diese gilt bis zum Ende des zugehörigen Aufrufs von zahlEinlesen() cout << "Gib eine Zahl ein (Abbruch mit 0): "; cin >> zahl; if (zahl != 0) { zahlEinlesen(); // nach diesem Aufruf ist die im Aufruf neu deklarierte Variable zahl // wieder freigegeben, sodass wir jetzt wieder auf die oben deklarierte // Variable zugreifen können cout << "Die war " << zahl << endl; } // nach dieser Zeile wird der Speicher der oben deklarierten Variable zahl // wieder freigegeben, wir können dann nicht mehr auf diese zugreifen // das heißt auch: nach dieser Ausgabe sind die Zahlen weg, // wir können nicht mehr darauf zugreifen } struct ListenElement { int wert; // unser eigentlicher Datentyp ListenElement *next; // Zeiger auf das nächste ListenElement // Zeiger werden mit einem vorangestellten * markiert }; ListenElement* zahlEinlesenMitListen(void) { // liest Zahlen ein und gibt den Zeiger auf das erste Element zurück // (Zahlen sind in der Liste in umgekehrter Reihenfolge der Eingabe) // // erzeuge leere Liste ListenElement *anker; // anker ist der Zeiger (deshalb der vorangestellte *) auf ein ListenElement anker = NULL; // NULL sollte dem Compiler bekannt sein und ist quasi die spezielle // Speicheradresse 0. Diese wird verwendet, um zu kennzeichnen, dass auf kein Element // verwiesen wird. Alternative Darstellung für Schreibfaule (nicht empfohlen): 0 int zahl; ListenElement *neuesElement; // wird in der Schleife verwendet für die // neu generierten ListenElemente, s. Kommentar weiter unten cout << "Gib eine Zahl ein (Abbruch mit 0): "; cin >> zahl; while (zahl != 0) { // füge zahl als neues erstes Element in die Liste ein, dazu: // - reserviere Speicherplatz für ein neues ListenElement // - kopiere die eingelesene Zahl in dieses neue ListenElement // - merke mit dem next-Zeiger im ListenElement, wo die Liste // im Speicher fortgesetzt wird neuesElement = new ListenElement; // new reserviert Speicherplatz für eine // Variable vom Typ und gibt die Adresse, an der dieser Speicherplatz // sich befindet, als Ergebnis zurück neuesElement->wert = zahl; // kopiert die zahl in das neuesElement (Zuweisung wie schon immer gemacht) // bei Zuweisung auf einen Selektor in einem zusammengesetzten Datentyp (struct) // verwenden wir statt dem . die Dereferenzierung (in Zeichen: ->) //neuesElement->next = anker; // beachte: anker ist ein Zeiger (also ein Speicheradresse) // und genau diese wollen wir zuweisen (also nicht den Wert, auf den der Zeiger zeigt) // nicht vergessen: anker muss noch auf das neue erste Element verweisen // Alternative Schreibweise: *neuesElement spricht das struct direkt an // das heißt auch, dass wir den Selektor mit einem . ansprechen können (*neuesElement).next = anker; // üblich ist aber die '->' Schreibweise // diese Zeile alternativ zu der jetzt 5 Zeilen drüber auskommentierten anker = neuesElement; cout << "Gib eine Zahl ein (Abbruch mit 0): "; cin >> zahl; } return anker; } void ListeMitZahlenAusgeben(ListenElement *anker) { // Idee: solange Elemente da sind, diese ausgeben, ansonsten jeweils auf das nächste Element // in der Liste vorrücken ListenElement *aktElem = anker; while (aktElem != NULL) { cout << "Nächste Element ist die " << aktElem->wert << endl; // nun noch auf das nächste Element vorrücken aktElem = aktElem->next; } // alternative: rekursive Lösung // if (aktElem != NULL) // { // cout << "Nächste Element ist die " << aktElem->wert << endl; // } // else // { // ListeMitZahlenAusgeben(aktElement->next); // } // da aktElement nie was zugewiesen wird, könnte man bei der rekursiven Variante // auch die Variable anker direkt verwenden } int main(void) { // zahlEinlesen(); ListenElement *anker; anker = zahlEinlesenMitListen(); ListeMitZahlenAusgeben(anker); return 0; }