2016-04-12 20 views
1

So ein Freund von mir nimmt einen seiner ersten CS-Klassen und erwähnt, dass er Rekursion in seinem allerersten Programm verwendet. Er schickt mir den Code unten. Auf Anhieb bemerkte ich, dass er den Rückgabewert seines rekursiven Anrufs nicht abfing und ich nahm an, dass es nicht funktionieren würde. Aber er besteht darauf, dass es funktioniert, also probiere ich sein Programm aus und zu meiner Überraschung funktioniert es genau wie erwartet. Ignoriert man die Tatsache, dass dies ein dummer Weg ist, um von A nach B zu kommen, warum funktioniert das überhaupt?Warum funktioniert diese rekursive Funktion?

Ich spielte mit dem, was er mir geschickt hat und fügte nach der if-Anweisung eine cout hinzu. Außerdem sind der erste Code-Teil und der zweite Teil identisch.

Wenn ich Eingabe der für das erste Programm folgende, hier ist was ich ...

eine Nummer eingeben: 10

Sie gemacht haben: 10 Ist das richtig? (Y/N): N

eine Nummer eingeben: 12

Sie gemacht haben: 12 Ist das richtig? (Y/N): Y

Haupt() = 12

Und dann, wenn ich das gleiche mit dem zweiten Programm zu tun, hier ist was ich ...

a Geben Sie Nummer: 10

Sie haben eingegeben: 10 Ist das korrekt? (Y/N): N

eine Nummer eingeben: 12

Sie gemacht haben: 12 Ist das richtig? (Y/N): Y

Haupt() = 6300096

Was ist los !?

#include <iostream> 
#include <cstring> 
#include <cctype> 

using namespace std; 

int getNum() 
{ 
    cout << "Enter a Number: "; 
    int x; 
    cin >> x; 
    cin.ignore(100, '\n'); 

    while(x < 0) { 
     cout << "Please enter amount greater than 0: "; 
     cin >> x; 
     cin.ignore(100, '\n'); 
    } 

    cout << "You entered: " << x << " Is this correct? (Y/N): "; 
    char response; 
    cin >> response; 
    cin.ignore(100, '\n'); 

    if (response != 'Y') { 
     getNum(); 
    } else { 
     return x; 
    } 
} 

int main() { 

    cout << "\nmain() = " << getNum() << endl; 

    return 0; 
} 

Der einzige Unterschied zwischen der Spitze und der Unterseite ist eine cout Anweisung nach der if-Anweisung.

#include <iostream> 
#include <cstring> 
#include <cctype> 

using namespace std; 

int getNum() 
{ 
    cout << "Enter a Number: "; 
    int x; 
    cin >> x; 
    cin.ignore(100, '\n'); 

    while(x < 0) { 
     cout << "Please enter amount greater than 0: "; 
     cin >> x; 
     cin.ignore(100, '\n'); 
    } 

    cout << "You entered: " << x << " Is this correct? (Y/N): "; 
    char response; 
    cin >> response; 
    cin.ignore(100, '\n'); 

    if (response != 'Y') { 
     getNum(); 
    } else { 
     return x; 
    } 
    cout << "returning... " << x; 
} 

int main() { 

    cout << "\nmain() = " << getNum() << endl; 

    return 0; 
} 
+3

In 'if (Antwort! = 'Y')', sollten Sie 'getNum();' nicht zurückgeben? Wenn du es so schreibst, wenn du 'Antwort! =' Y''est, gibst du nie etwas zurück, also ist die Tatsache, dass dein erstes Programm funktioniert, hauptsächlich Glück. – tforgione

+1

Ja, du hast Recht, aber ich frage nach dem Glücksteil. –

+0

Meine schlechte, habe deine Frage nicht verstanden. – tforgione

Antwort

6

Auf der Maschinencodeebene wird normalerweise in einem bestimmten Prozessorregister ein ausreichend kleines Funktionsergebnis zurückgegeben.

Formal der Code Verhalten nicht definiert durch nicht return Aussage in einigen Anrufen von getNum ausgeführt wird, aber was passiert, ist dies wahrscheinlich:

  1. getNum() genannt wird, Benutzer antwortet N.

  2. getNum() ruft sich rekursiv, Benutzerantwort Y.

  3. getNum() führt return x; aus. Bei einer typischen C++ Implementierung dieser den Rückgabewert in einem Register legt, nennen sie es R.

  4. Ausführung liefert bis zu getNum() (ursprünglichem Anruf), die jetzt durch die Ausführung kehrt durch das Ende der Funktion übergibt, keine return.

  5. Der aufrufende Code findet den Wert im Register R wie erwartet.

So kann es “ Arbeit ”.

Aber es ist formal Undefined Behavior, und mit einigen anderen Compiler und/oder Optionen, könnte es nicht funktionieren.

+1

Dies erklärt auch, warum es nicht funktioniert mit 'cout <<" zurück ... "<< x;' - dieser Code ist selbst mit "R" .... –

+0

@TonyD: Guter Punkt, danke. :) –

2

In C++ Compiler nicht überprüfen gründlich die Funktion ohne return-Anweisung seinen Fluss endet, weil er alle Kontrolle zu überprüfen Pfade nicht leichte Aufgabe ist. Das Verhalten dieses Codes ist nicht definiert. Was tatsächlich geschieht, hängt von der Aufrufkonvention ab.

Ich glaube, sie haben nur return vor getNum() vergessen. Es wird funktionieren und wird den Stack nicht verschmutzen, wenn die Tail-Rekursion optimiert wird.

Dieser Code ist seltsam für erste CS-Klassen.

Verwandte Themen