C# Rekursion - Frage

damien

Enthusiast
Thread Starter
Mitglied seit
08.12.2003
Beiträge
3.955
Hi,

könnte mir jemand bitte erklären, warum die Variable "arrayPointer" den Wert 1
hat, nachdem man die Methode "calculateCombinations(int arrayPointer, int input)" mit calculateCombinations(4,5); aufgerufen hat ? Nach dem das Ding durchläuft hat arrayPointer den Wert 0. Dann werden die Werte ausgegeben und die Methode wird rekursiv aufgerufen aber dann hat arrayPointer den Wert 1 und ich verstehe einfach nicht warum ! Wäre für Hilfe sehr dankbar !

Code:
using System;

namespace Hausaufgabe_1
{
    //Diese Klasse soll globale Variablen "simulieren"
    
    public static class GlobalMoneyChange
    {
        //Es wird ein Array erstellt, das die gueltigen Muenzen enthaelt

        public static int[] arrayOfValidMoney = { 1, 2, 5, 10, 50 };

        /*2 Variablen, die den Anfang und das Ende des Arrays darstellen
        *zum besseren Rechnen und um einer ArrayIndexOutOfBoundsException vorzubeugen
        */

        public static int aovmMin = 0;
        public static int aovmMax = 4;

        //Ein temproraeres Array der Groesse arrayOfValidMoney zum Rechnen

        public static int[] arrayOfCalc = new int[5];

        //Ein Counter, der die gesamten Wechselkombinationen zaehlt

        public static int combinationCounter = 0;

    }

    class ChangeMoney
    {   
        static void Main()
        {
           //Das Menue wird gestartet

            printMenu();
        }

        static void printMenu()
        {
            //Das Menue wird ausgegeben

            Console.WriteLine();
            Console.WriteLine("Willkommen zum Geldwechselprogramm");
            Console.WriteLine();
            Console.WriteLine("Es sind die Muenzen 1, 2, 5, 10 und 50 verfuegbar");
            Console.WriteLine("Geben Sie bitte den zu wechselnden Betrag ein: ");
            Console.WriteLine("Die Eingabe von \"0\" beendet das Programm");

            /*Die Eingabe von der Tastatur wird gestartet.
             * Falls "0" eingegeben wird, dann wird das Programm beendet,
             * andernfalls wird die Berechnung gestartet und alle Kombinationen
             * werden ausgegeben.
             */ 
            
            int input = keybInput();
            
            if (input == 0)
            {
                Console.WriteLine("Programm beendet\n");
            }
            else
            {
                Console.Write("\n50 10 05 02 01\n");
                Console.Write("-----------------\n");
                calculateCombinations(GlobalMoneyChange.aovmMax, input);
                printOnConsole();
                Console.Write("-----------------");
                Console.WriteLine("\nWechselkombinationen: " + GlobalMoneyChange.combinationCounter +"\n");
            }
        }
        
        static int keybInput()
        {
            /* Die Eingabe erfolgt hier,
             * falls eine Exception auftritt wird sie aufgefangen und behandelt.
             * Der Benutzer wird zu einer erneuten Aufgabe aufgefordert
             */

            int input;
            try
            {
                input = Convert.ToInt32(Console.ReadLine());
                    
                    return input;
                
            }
            catch
            {
                Console.WriteLine("Falsche Eingabe, bitte noch ein mal: ");
                keybInput();

                return 0;
            }
        }

        static void calculateCombinations(int helpVar, int input)
        {

            if (helpVar == GlobalMoneyChange.aovmMin)
            {
                GlobalMoneyChange.arrayOfCalc[helpVar] = input;
                printOnConsole();
                GlobalMoneyChange.combinationCounter++;
            }
            else
            {
                int value = (input / GlobalMoneyChange.arrayOfValidMoney[helpVar]);
                for (int counter = value; counter >= 0; counter--)
                {
                    GlobalMoneyChange.arrayOfCalc[helpVar] = counter;
                    int inputRest = (input - (counter * GlobalMoneyChange.arrayOfValidMoney[helpVar]));
                    calculateCombinations(helpVar - 1, inputRest);
                }
            }
        }

        static void printOnConsole()
        {
            /* Hier erfolgt die Ausgabe. Es wird eine Schleife durchlaufen,
             * in der jede Position des "temporaeren" Arrays ausgegeben wird
             */

            for (int counter = GlobalMoneyChange.aovmMax; counter >= GlobalMoneyChange.aovmMin; counter--)
            {
                Console.Write(" " + GlobalMoneyChange.arrayOfCalc[counter] + " ");
            }
            Console.Write("\n");
        }   
    }
}
 
Zuletzt bearbeitet:
Wenn Du diese Anzeige nicht sehen willst, registriere Dich und/oder logge Dich ein.
Was genau meinst du denn mit "durchgelaufen". An Welcher Stelle?
calculateCombinations() wird durch die Rekursion ja nicht nur 2x durchgelaufen...also ziemlich schwierig für mich zu raten WANN welches DING wo "Durchgelaufen" ist, und welchen wert annehmen sollte.

In jedem Fall wird calculateCombinations() innerhalb des ersten Aufrufs von calculateCombinations() 4x gestartet, jeder dieser Aufrufe startet die Methode nochmal...die auch wieder die Methode aufrufen. Wie das bei Rekursion so ist, wird die Aufrufende Methode aber erst beendet, wenn all "Kinder" beendet sind. Vielleicht liegt ja darin dein problem...im Moment kann ich mangels präziser Infos nur Glaskugeln.
 
Zuletzt bearbeitet:
Ich hab leider nicht so viel Ahnung von C# aber unter C++ kann das so nicht funktionieren. Dein Arraypointer heißt zwar Pointer aber er ist keiner. In C++ würde man das über einen richtigen Pointer machen. Also CallByRef und nicht CallByValue. Dein "Pointer" ist jedesmal eine Kopie des Orginals. Ich erklär das mal an einem Beispiel

calc(in a)
{
a:=3
}

a:=1
calc(a)

Resultat: a ist immernoch 1, da in der Funktion eine Kopie erstellt wird und diese nach dem Funktionsende vernichtet wird. Ohne Returnvalue wird die Funktion also nie etwas sinnvolles machen.

Gut ich nehme mal an das war von dir aber so gewollt. Nun kommen wir also zur Rekusion. Deine Funktion ruft sich unter bestimmten Bedingungen selber auf. Dabei entsteht eine Hirachie, die abgearbeitet wird. Wie und Wann er welchen Zweig abarbeitet kann ich dir nicht sagen. Dein Fehler könnte aber damit zu tun haben, dass ein Zeig einfach zuende ist und ein völlig anderer, in dem dann dein Pointer den Wert 1 hat, abgearbeitet wird. Wie aber hier schon geschrieben wurde, kann man da nur in die Glaskugel schaun.
 
c# kennt keine Pointer im eigentlichen Sinne wie C++. Ich denke Begriff "pointer" ist hier einfach zur ungluecklich gewaehlt fuer den Index des Arrays.

Hast du schonmal den Debugger verwendet?
 
Zuletzt bearbeitet:
Das Programm tut was es soll. Der Pointer ist kein richtiger Pointer, der Name ist schlecht gewählt. Den Debugger habe ich auch benutzt. Wenn ich mit calculateCombinations(4,5); starte, dann hat der arrayPointer am Ende den Wert 0 und beim Aufruf der Rekursion dann plötzlich den Wert 1 und das ist es was ich nicht verstehe und hoffe, dass mir das jemand erklären kann.
 
Ich denke das Problem liegt daran das ArrayPoninter hier deklariert und initialisiert wird:
static void calculateCombinations(int arrayPointer, int input)
also bei calculateCombinations(3,5) wird 3 arrayPointer zugewiesen.
Dieser ArrayPointer existiert jetzt aber nur in calculateCombinations.
printOnConsole benutzt jetzt auch eine ArrayPointer Variable, die aber in ihrem Bereich eigentlich nicht deklariert ist. Eigentlich müßte man arrayPointer in PrintOnConsole mit int deklarieren (zB for (int arrayPointer = ...) und es wäre auch nur lokal verfügbar.
Auf jeden Fall sollte eine in funktion 1 deklarierte variable nicht in funktion 2 deklariert sein...
 
Ich hab den Code nun mal geupdated. arrayPointer ist jetzt helpVar und in der Ausgabemethode habe ich arrayPointer durch "counter" ersetzt.

Ich starte die Methode calculateCombinations(4,5);

Nach 4 durchläufen haben beide Variablen den Wert 0:

http://www.abload.de/img/forumdeluxxxnr.jpg

Jetzt wird das Array Stelle für Stelle ausgegeben.
Nachdem das geschehen ist wird die Methode rekursiv aufgerufen:

http://www.abload.de/img/forumdeluxx21iq.jpg

helpVar hat plötzlich den Wer 1, aber warum zum Teufel ? Das ist es was ich einfach nicht verstehe, aber verstehen will/muss !!!!

Die Methode wird natürlich wieder rekursiv aufgerufen, muss ja so sein... Plötzlich ist helpVar = 2 und input = 5 ... Wie kann das sein ?

http://www.abload.de/img/forumdeluxx3nip.jpg

Ich schnalle das einfach nicht...
 
du hast die rekursion noch nicht so richtig begriffen.
hier der ablauf

Code:
calculate(4,5)
  value = 5 / 50 = 0
  inputrest = 5
  counter = 0
  calculate(3,5)
    value = 5 / 10 = 0
    inputrest = 5
    counter = 0
    calculate(2,5)
      value = 5 / 5 = 1
      inputrest = 0
      counter = 1 // Hier ist der Fehler
      calculate(1,0)
        value = 0 / 2 = 0
	inputrest = 0 
	counter = 0
	calculate(0,0)
	  print
      counter = 0
	calculate(1,0)
	  value = 0 / 2 = 0
	  inputrest = 0 
          counter = 0
          calculate(0,0)
	    print
 
Was meinst du denn mit Fehler ? Kannst du das vllt näher beschreiben bitte ?

Code:
calculate(4,5)
  value = 5 / 50 = 0
  inputrest = 5
  counter = 0
  calculate(3,5)
    value = 5 / 10 = 0
    inputrest = 5
    counter = 0
    calculate(2,5)
      value = 5 / 5 = 1
      inputrest = 0
      counter = 1 // Hier ist der Fehler
      calculate(1,0)
        value = 0 / 2 = 0
	inputrest = 0 
	counter = 0
	calculate(0,0)
	  print
      counter = 0
	calculate(1,0) // Hier fängt er wieder mit der 1 an, warum ??????
	  value = 0 / 2 = 0
	  inputrest = 0 
          counter = 0
          calculate(0,0)
	    print
 
Zuletzt bearbeitet:
Code:
1:calculate(4,5)
  value = 5 / 50 = 0
  inputrest = 5
  counter = 0
  2:calculate(3,5)
    value = 5 / 10 = 0
    inputrest = 5
    counter = 0
    3:calculate(2,5)
      value = 5 / 5 = 1
      inputrest = 0
      counter = 1 // Hier ist der Fehler
      4:calculate(1,0)
        value = 0 / 2 = 0
	inputrest = 0 
	counter = 0
	calculate(0,0)
	  print
      counter = 0
	5:calculate(1,0) // Hier fängt er wieder mit der 1 an, warum ??????
	  value = 0 / 2 = 0
	  inputrest = 0 
          counter = 0
          calculate(0,0)
	    print

Ich hab es oben schon erklärt. Rekusion heißt, dass eine Hirachie aufgebaut wird und diese dann abgearbeitet. Bis zur Zeile 4 wird die Zeile immer vom Vorgänger aufgerufen. Wenn man ich deine Funktion genau anschaut steht Bei Zeile 3 folgendes:

for (int counter = 1; counter >= 0; counter--)
{
GlobalMoneyChange.arrayOfCalc[2] = counter;
...
calculateCombinations(helpVar - 1, inputRest);
}
Das erzeugt 2 Funktionsaufrufe und zwar genau Zeile 4 und 5. Ich weiß nicht gnau was du vor hattest aber da ist erstmal dein "Fehler". Mach was draus :)
 
Hi,

erst mal vielen Dank, dass du/Ihr Zeit in den Thread investiert und mir helft.

Mit "Fehler" meinst du Denkfehler oder ? Denn das Programm funktioniert ja so wie es soll... bzw. die Ausgabe ist korrekt.
 
Mit "Fehler" meine ich deine Schilderung von oben. Die Prozedure wird augenscheinlich plötzlich mit den Falschen Werten aufgerufen. Ich hab es aber in Anführungsstriche geschrieben, da es sich ja um Rekusion handelt und das Programm eigentlich alles richtig gemacht hat und auch du eigentlich keinen Denkfehler hattest. Du hast dich vermutlich nur gewundert. Ob es an der Funktionalität etwas ändert kann ich nicht beurteilen. Du weißt aber sicherlich bereits ob das Ergebniss deiner Prozedure auch richtig ist oder ob der "Fehler" auch ein Fehler ist :)
 
Ok, vielen Dank :)
 
Hardwareluxx setzt keine externen Werbe- und Tracking-Cookies ein. Auf unserer Webseite finden Sie nur noch Cookies nach berechtigtem Interesse (Art. 6 Abs. 1 Satz 1 lit. f DSGVO) oder eigene funktionelle Cookies. Durch die Nutzung unserer Webseite erklären Sie sich damit einverstanden, dass wir diese Cookies setzen. Mehr Informationen und Möglichkeiten zur Einstellung unserer Cookies finden Sie in unserer Datenschutzerklärung.


Zurück
Oben Unten refresh