Frage: Programm nicht verstanden...
-
Hallo Leute,
bin neu hier. Habe eine kurze Frage. Schreibe bald eine Klausur im Programmieren und habe hier ein kleines Programm wo ich ein paar Kleinigkeiten nicht ganz verstehe.
Folgendes Programm:#include <iostream> using namespace std; void rek(int i){ if (i>0){ cout << i; rek(i-1); for ( int k=0; k<i; k++){ cout << i; } } } int main () { rek(4); return 0; }
Die Ausgabe lautet: 43211223334444
Nun mein Problem:
das "4321" verstehe ich soweit.
im letzten Lauf ist das i = 1 der geht also in die if Schleife, gibt die 1 (von "4321") aus. Dann geht der ja in die for Schleife. Dort wird k=0 deklariert. -> solange k < i in dem 1. Fall also 0<1 dann k++ und cout << i.
Nun ist mein i ja noch 1 also gibt der noch eine 1 aus.
So nun das eigentliche Problem.
Der macht das solange, bis k nicht mehr < i ist bzw die Schleifenbedingung nicht mehr zutrifft.
Aber wieso wird dann i verändert?
Es ist in der Schleife ja nur die Rede von k und k++ es wird also nur k hochgezählt und nur i ausgegeben. i dürfte sich ja dann eigentlich nicht verändern. woher kommen also die anderen ausgaben (also ... 22 333 4444) ??
Ich habe es mit Breakpoints versucht ich komme aber nicht hinter.ich hoffe ihr könnt mir helfen
Danke schonmal
Gruß
Piro411
-
Denkfehler: i wird nicht verändert.
Was macht er denn, wenn er mit der Schleife fertig ist? Antwort: Die Funktion ist dann fertig und kehrt an den Ort des Aufrufs zurück. Wo wurde sie aufgerufen? Wenn du dies beantwortest, wirst du den Rest (und damit auch Rekursion) verstehen.
-
Dann bin ich doch sozusagen wieder in der main bei rek (4)- springe dann also oben wieder in die funktion und gebe wieder i aus mit i -1... oder? dann würde ich aber wieder bei 4 anfangen und nicht bei 22 333 4444...??
-
aahhh ich meine ich habs-> ich gehe dann in die main fange mit rek(4) wieder an gehe in die forschleife, wo nun k nicht mehr=0 sondern wegen dem k++ nun 1 geworden ist also wird 1<i (i ist ja dann 2 durch dem i-1 udn dann gibt der 2 aus dann wird k zu 2 wegen k++ ... fange wieder bei rek(4) an springe hoch etc und so weiter bis ich 4321 1 22 333 4444 habe oder??
-
rek(0) kehrt zu rek(1) zurück, das kehrt dann wieder an rek(2) zurück und so weiter.
-
piro411 schrieb:
ich gehe dann in die main fange mit rek(4) wieder an gehe in die forschleife,
Zwischen an und gehe passiert noch etwas wichtiges.
-
Wenn du die Werte bei der Ausgabe etwas anders gruppierst, siehst du es leichter:
4 3 2 1 1 22 333 4444
-
also ich bin jetzt so weit:
das programm gibt ja 4,3,2,1 aus BEVOR es in die for schleife geht noch oder?
dann habe ich 4,3,2,1 ausgegeben mein i is somit 1 und dann gehe ich in die for schleife.
dort IN der For schleife---> DIE FOR SCHLEIFE GEHT NOCH VON EINER 4 aus die in die funktion übergeben wurde oder? also steht da im endeffekt int k = 0; 0<4, k++ oder?
das heisst aber der würde dann in der for schleife zu erst ne 4 ausgeben?!OODER ( anderer Ansatz der for schleife)
nach dem der 4,3,2,1 ausgegeben hat gibt der mein i=1 in die for schleife weiter also 0<1 cout <<i --> 1 wird ausgegeben
dann im nächsten schritt wird k hochgezählt also steht da 1<1 das trifft ja nicht zu deshalb müsste er doch aus der forschleife springen und das programm muss beendet werden?!
ich komm da einfach nicht hinter...
-
nach dem 2. schleifendurchlauf der for schleife wird i von 1 zu 2 umgesetzt. habe eben nen breakpoint dahin gesetzt. wie geschieht das? also wieso wird i =2 ?
wenn mir einer das sagen könnte, also wieso nachdem 0<1 nicht mehr zutreffen kann in der for schleife-- wieso genau da i auf 2 gesetzt wird, wäre das super. denn dann weiss ich wie das ding klappt
-
piro411 schrieb:
dann im nächsten schritt wird k hochgezählt also steht da 1<1 das trifft ja nicht zu deshalb müsste er doch aus der forschleife springen und das programm muss beendet werden?!
Nein, die Schleife ist fertig und die Funktion wird verlassen.
Nachdem das aber der Aufruf rek(1) war, landest du im Aufruf rek(2), und zwar direkt bei der inneren for-Schleife. Dort läuft die Schleife bis 2<2 und dann wird die Funktion beendet und kehrt zu rek(3) zurück und zwar – du ahnst es schon – zur inneren for-Schleife.
-
piro411 schrieb:
nach dem 2. schleifendurchlauf der for schleife wird i von 1 zu 2 umgesetzt. habe eben nen breakpoint dahin gesetzt. wie geschieht das? also wieso wird i =2 ?
Weil du von rek(1) zu rek(2) zurückspringst und da ist i=2.
-
[quote="nman"]
piro411 schrieb:
Nachdem das aber der Aufruf rek(1) war, landest du im Aufruf rek(2), und zwar direkt bei der inneren for-Schleife.
wieso macht der das denn? also wieso geht der nach rek(1) wieder mit rek(2) in die for schleife bzw. wieso macht der das sozusagen rückwärts?
also geht der einfach dei werte durch die i hatte bevor er zum 1. mal in die for schleife gegangen ist??
-
Ok ich aber wieso geht der mit rek(2) wieder in die for schleife??
geht der einfach alle werte durch, die i hatte, bevor er zum ersten mal in die for schleife gegangen ist? also dann halt sozusagen die ausgegebenen werte (4321) nochmal durch die for schleife hoch bis zur 4 und dann erst programm ende??
-
Rekursion scheint an dir noch vorbei zu gehen. Machen wir mal eine Nummer einfacher:
#include <iostream> using namespace std; void rek(int i) { if (i > 0) { cout << "Rekursionsfunktion mit i = " << i << ". Ausgabe am Anfang.\n" << "Rufe nun Funktion mit i = " << i - 1 << " auf.\n"; rek(i - 1); cout << "Rekursionsfunktion mit i = " << i << ". Ausgabe am Ende." << " Kehre nun zurück.\n"; } } int main() { rek(4); }
Verstehst du die Ausgabe dieses Programms? Erklär mal.
-
Schau dir mal mit diesem hässlichen aber etwas simpleren Programm an, wie rekursive Funktionsaufrufe ablaufen:
#include <iostream> #include <string> void rek(unsigned i) { if (i >= 3) return; std::string s = ""; for (unsigned j = 0; j<i; ++j) s += " | "; std::cout << s << "rek: i=" << i << " (vorher)\n"; rek(i+1); std::cout << s << "rek: i=" << i << " (nachher)\n"; } int main() { rek(0); }
Ist ziemlich ähnlich wie dein ursprüngliches Programm, aber vielleicht verstehst du es durch die Ausgabe etwas besser:
rek: i=0 (vorher) | rek: i=1 (vorher) | | rek: i=2 (vorher) | | rek: i=2 (nachher) | rek: i=1 (nachher) rek: i=0 (nachher)
Setz am besten mal einen Breakpoint vor dem rek-Aufruf und geh dann mit dem Debugger Schritt für Schritt durch.
edit: Zu langsam.
-
ACHSOOOO!!!!! ich glaub jetzt habe ich es.
Bei der Rekursion gehe ich, sobald ich am "Ende" meiner bedingung (hier zum Beispiel i>0) angekommen bin, meine Werte wieder bis zum Anfang durch.
Also wenn ich 4 3 2 1 habe gehe ich (Bei meinem Programm jetzt) in die Forschleife und zwar dann sozusagen rückwärts erst mit i=1 dann mit i =2 .... bis i =4, also meinen Anfangswert dann halt und gebe dann das was die Forschleife halt macht mit diesen Werten aus.
Ich gehe nachdem die Bedingung i>0 also nicht mehr zutrifft wieder Schritt für Schritt zurück.
Ist das soweit richtig?SeppJ und nman --> Eure Programme haben es verdeutlicht! Danke
-
piro411 schrieb:
Ist das soweit richtig?
Ich habe immer noch den Eindruck, dass du es nicht wirklich verstanden hast.
SeppJ und nman --> Eure Programme haben es verdeutlicht! Danke
Kannst du dies immer noch erklären?
#include <iostream> using namespace std; void rek(int i) { if (i > 0) { cout << "Rekursionsfunktion mit i = " << i << ". Ausgabe am Anfang.\n" << "Rufe nun Funktion mit i = " << i - 1 << " auf.\n"; rek(i - 1); cout << "Rekursionsfunktion mit i = " << i << ". Ausgabe in der Mitte.\n" << "Rufe nun Funktion mit i = " << i - 2 << " auf.\n"; rek(i - 2); cout << "Rekursionsfunktion mit i = " << i << ". Ausgabe am Ende." << " Kehre nun zurück.\n"; } else cout << "Aufruf mit i = " << i << ", kehre sofort zurück.\n"; } int main() { rek(3); }
Prüf auch deine Vorstellung auch mal an ein paar größeren Zahlen als 3 beim Aufruf in der main, ob du wirklich richtig liegst.