Frage zur Rekursion



  • Wir haben von unserem Dozenten die Aufgabe bekommen die Fakultät rekursiv zu berechnen und uns jedes mal die Adresse der Variable ausgeben zu lassen.
    Erstmal das Programm:

    //Aufgabe 10.1 Fakultät Rekursiv berechnen
    #include <stdio.h>
    
    int facult(int n);
    
    int main(void)
    {
    
    	int iVal = 0;
    	int iResult;
    
    	printf("Bitte geben sie die Zahl ein,\nvon der die Fakultaet berechnet werden soll: ");
    	scanf("%d", &iVal);
    
    	iResult = facult(iVal);
    	printf("\nDas Ergebniss der Berechnung war: %d\n\n", iResult);
    
    	system("pause");
    	return 0;
    }
    
    int facult(int n)
    {
    	printf("Adresse von n:\t%p\n", &n);
    
    	if(n == 1)
    		return 1;
    	if(n == 2)
    		return 2;
    
    	return facult(n-1)*n;
    }
    

    Die Ausgabe des Programms:

    Bitte geben sie die Zahl ein,
    von der die Fakultaet berechnet werden soll: 8
    Adresse von n:  001BFB40
    Adresse von n:  001BFA68
    Adresse von n:  001BF990
    Adresse von n:  001BF8B8
    Adresse von n:  001BF7E0
    Adresse von n:  001BF708
    Adresse von n:  001BF630
    
    Das Ergebniss der Berechnung war: 40320
    
    Drücken Sie eine beliebige Taste . . .
    

    Meiner Meinung nach sollte die Adreese doch um die Größe von int, also um 32 Bit
    größer werden. Was ich nicht verstehe ist warum die Adresse kleiner wird und warum sich die Adresse um 217Bit, also um 27 Byte verschiebt?
    Meinen Dozenten kann ich leider nicht Fragen da er keine Ahnung von C hat.

    LG Jan


  • Mod

    Vermutlich Debugcode, der Stackcorruption erkennen soll. Erstell mal eine optimierte Version. Wenn du Assembler einigermaßen lesen kannst, kannst du dir ja auch mal angucken, was der Compiler da genau macht.



  • jan91 schrieb:

    Meiner Meinung nach sollte die Adreese doch um die Größe von int, also um 32 Bit

    Nein. Funtionsparameter, Rücksprungadresse, Basepointer, Zwischenergebnisse als unsichtbare lokale Variablen, die können auch alle auf dem Stack landen. Also mindestens mal die Rücksprungadresse, dann biste schon bei 8 Bytes. Mehr nach Belieben des Compilers.

    jan91 schrieb:

    größer werden. Was ich nicht verstehe ist warum die Adresse kleiner wird

    Nein, der Stack wächst traditionell nach unten. Grund: Programmspeicher ist ganz am Anfang (feste Größe), dann kommen die globalen Variablen (feste Größe), dann der Freispiecher (Heap, variable Größe), dann kommt eine ganze Weile lange nixhts. Und am oberen Ende des Speichers kommt der Stack. Und der STack wächst nach unten und der Heap nach oben. Erst wenn sie sich berühren ist der Speicher alle. So kann man den Speicher total ausnutzen, egal ob man mehr Stack oder mehr Heap braucht. So war es früher. Heute nicht mehr. Aber traditionell wächst der Stack weiterhin nach unten.

    jan91 schrieb:

    und warum sich die Adresse um 217Bit, also um 27 Byte verschiebt?

    27 ist schon sehr ungewöhnlich.
    Aber hast Dich ja auch verrechnet. Es sind 0x280xd8 Bytes, also 40216 Bytes.
    Da müßte man schon ins Compilat (in den erzeugten Assemblercode) schauen, um zu sehen, was der Compiler da alles ablegt.
    n, Rücksprungadresse, Basepointer, die beiden Argumente von printf, sind erst 20 Bytes, mir fehlen noch weitere Ideen, um so viel Speicher zu verbrauchen. SeppJs These finde ich gut.



  • 0x001BFB40 - 0x001BFA68 = 0xd8 = 216 Byte.

    Die Variablen werden auf dem Stack abgelegt.
    Der wird von oben nach unten gefüllt.
    Dort landen aber auch noch andere Werte wie die Rücksprungadresse der Funktion.



  • Dankeschön
    Hat mir sehr geholfen.
    Natürlich wars der Debugcode...
    Im Release Modus brauch er pro Funktionsaufruf nur noch 8 Byte.
    Vermutlich 4 für den Integer Parameter und 4 für die Rücksprungadresse.
    Heftig was der Compiler da an Debuginformation ablegt, braucht pro Aufruf das 27-fache an Speicherplatz.

    LG Jan


  • Mod

    Die Debugsymbole werden dort nicht abgelegt, die sind fest am Ende der Exe eingebaut und ändern am Programmablauf gar nix. Da werden bestimmte magische Werte zwischen die Stackframes geschrieben (z.B. 0xDEADBEEF oder etwas anderes, irgendwo ist das dokumentiert) und wenn eine Funktion verlassen wird, wird geguckt, ob sich da irgendetwas verändert hat. Wenn da andere Werte stehen, hat jemand über Arraygrenzen geschrieben oder anderen Unfug gemacht. Wenn in deinem Programm plötzlich der Wert 0xDEADBEEF irgendwo auftaucht, wurde über irgendwelche Grezen gelesen.


Anmelden zum Antworten