Interpreter-Fehler Endlosschleife zur Laufzeit aber warum?

Java:
public class LaufzeitFehler1 {

    public static void doSomething(int[] feld) {
        while (feld.length > 0)
        doSomethingOther(feld);
    }
   
    public static void doSomethingOther(int[] feld) {
        int[] args = new int[feld.length - 1];
        for (int i = 0; i < args.length; i++)
            args[i] = feld[i] - 3;
        doSomething(args);
    }

    public static void main(String[] args) {
        doSomething(new int[] { 1, 2, 3 });
    }
}
Dieses Programm liefert zur Laufzeit eine Endlosschleife. Leider bin ich trotz mehrmaligem drüberschauen nicht fündig geworden, weshalb dieses Problem auftritt bzw. wo genau. Im beiligenden Lösungsskript ist lediglich angegeben, dass die while-Schleife immer true bleibt, da die doSomethingOther()-Methode keine Änderung in der anderen MEthode schafft. Jedoch ist es doch so, dass args an doSomething() übergeben wird und damit nach einigen Schleifendurchläufen die Länge = 0 wird und somit enden müsste :/

Bitte um Hilfe
 
Zuletzt bearbeitet von einem Moderator:
Hallo SaveDebagger,
Bash:
E:\>javac LaufzeitFehler1.java
LaufzeitFehler1.java:13: error: bad operand types for binary operator '-'
            args = feld - 3;
                        ^
  first type:  int[]
  second type: int
1 error
 
@juergenkulow das kommt nur daher, wenn man den Code zunächst nicht in Code-Tags packt. Dann wird [i] entfernt und von der Forensoftware als kursiv interpretiert - darum ist der Text nach seinem Code auch kursiv gesetzt :)
 
Hallo SaveDebagger,

Java:
public class LaufzeitFehler1 {
    static int zeilen=0;
    static int stack=0;
    public static void doSomething(int[] feld) {
    System.out.printf("Stack:%d Start doSomething\n",stack); // doSomething wird 3x mehr aufgerufen als beendet.
        while (feld.length > 0) { // Endlos, weil die feld.lenght in Schleife nicht kleiner wird.
            if (zeilen==7)
                System.exit(1);
            else
                zeilen=zeilen+1;
            System.out.printf("Rufe doSomethingOther auf feld.length:%d feld[0]:%d\n", feld.length,feld[0]);
            stack=stack+1;
            doSomethingOther(feld);
            stack=stack-1;
        }
        System.out.printf("Stack:%d Return doSomething\n",stack);
    }
  
    public static void doSomethingOther(int[] feld) {
        int[] args = new int[feld.length - 1];
        System.out.printf("Stack:%d Erzeuge neues int-Feld mit der Laenge: %d\n",stack, args.length);
        for (int i = 0; i < args.length; i++)
            args[i] = feld[i] - 3;
        //System.out.printf("Rufe doSomething auf args.length:%d feld[0]: %d \n", args.length,feld[0]);
        stack=stack+1;
        doSomething(args);
        stack=stack-1;
        //System.out.printf("Vernichte int-Feld mit der Laenge: %d \n",args.length);
    }

    public static void main(String[] args) {
        stack=stack+1;
        doSomething(new int[] { 1, 2, 3 });
    }
}
/*
E:\>java LaufzeitFehler1
Stack:1 Start doSomething
Rufe doSomethingOther auf feld.length:3 feld[0]:1
Stack:2 Erzeuge neues int-Feld mit der Laenge: 2
Stack:3 Start doSomething
Rufe doSomethingOther auf feld.length:2 feld[0]:-2
Stack:4 Erzeuge neues int-Feld mit der Laenge: 1
Stack:5 Start doSomething
Rufe doSomethingOther auf feld.length:1 feld[0]:-5
Stack:6 Erzeuge neues int-Feld mit der Laenge: 0
Stack:7 Start doSomething
Stack:7 Return doSomething
Rufe doSomethingOther auf feld.length:1 feld[0]:-5
Stack:6 Erzeuge neues int-Feld mit der Laenge: 0
Stack:7 Start doSomething
Stack:7 Return doSomething
Rufe doSomethingOther auf feld.length:1 feld[0]:-5
Stack:6 Erzeuge neues int-Feld mit der Laenge: 0
Stack:7 Start doSomething
Stack:7 Return doSomething
Rufe doSomethingOther auf feld.length:1 feld[0]:-5
Stack:6 Erzeuge neues int-Feld mit der Laenge: 0
Stack:7 Start doSomething
Stack:7 Return doSomething
Rufe doSomethingOther auf feld.length:1 feld[0]:-5
Stack:6 Erzeuge neues int-Feld mit der Laenge: 0
Stack:7 Start doSomething
Stack:7 Return doSomething

E:\>

*/
Java:
public class LaufzeitFeld {
    public static void mydoSomething(int[] feld) {
        int[] args;
        for (int j=feld.length; j>0 ; j--) {
            for (int i=0; i<feld.length; i++)
                System.out.printf("Feld[%d]:%2d ",i,feld[i]);
            System.out.println();
            args = new int[feld.length -1];
            for (int i = 0; i < args.length; i++)
                args[i] = feld[i] - 3;
            mydoSomething(args);
        }
    }

    public static void main(String[] args) {
        mydoSomething(new int[] { 1, 2, 3 });
    }
}

/*
E:\>java  LaufzeitFeld
Feld[0]: 1 Feld[1]: 2 Feld[2]: 3
Feld[0]:-2 Feld[1]:-1
Feld[0]:-5
Feld[0]:-2 Feld[1]:-1
Feld[0]:-5
Feld[0]: 1 Feld[1]: 2 Feld[2]: 3
Feld[0]:-2 Feld[1]:-1
Feld[0]:-5
Feld[0]:-2 Feld[1]:-1
Feld[0]:-5
Feld[0]: 1 Feld[1]: 2 Feld[2]: 3
Feld[0]:-2 Feld[1]:-1
Feld[0]:-5
Feld[0]:-2 Feld[1]:-1
Feld[0]:-5

E:\>
*/
 
Hallo SaveDebagger,

Java:
public class LaufzeitFehler1 {
    static int zeilen=0;
    static int stack=0;
    public static void doSomething(int[] feld) {
    System.out.printf("Stack:%d Start doSomething\n",stack); // doSomething wird 3x mehr aufgerufen als beendet.
        while (feld.length > 0) { // Endlos, weil die feld.lenght in Schleife nicht kleiner wird.
            if (zeilen==7)
                System.exit(1);
            else
                zeilen=zeilen+1;
            System.out.printf("Rufe doSomethingOther auf feld.length:%d feld[0]:%d\n", feld.length,feld[0]);
            stack=stack+1;
            doSomethingOther(feld);
            stack=stack-1;
        }
        System.out.printf("Stack:%d Return doSomething\n",stack);
    }

    public static void doSomethingOther(int[] feld) {
        int[] args = new int[feld.length - 1];
        System.out.printf("Stack:%d Erzeuge neues int-Feld mit der Laenge: %d\n",stack, args.length);
        for (int i = 0; i < args.length; i++)
            args[i] = feld[i] - 3;
        //System.out.printf("Rufe doSomething auf args.length:%d feld[0]: %d \n", args.length,feld[0]);
        stack=stack+1;
        doSomething(args);
        stack=stack-1;
        //System.out.printf("Vernichte int-Feld mit der Laenge: %d \n",args.length);
    }

    public static void main(String[] args) {
        stack=stack+1;
        doSomething(new int[] { 1, 2, 3 });
    }
}
/*
E:\>java LaufzeitFehler1
Stack:1 Start doSomething
Rufe doSomethingOther auf feld.length:3 feld[0]:1
Stack:2 Erzeuge neues int-Feld mit der Laenge: 2
Stack:3 Start doSomething
Rufe doSomethingOther auf feld.length:2 feld[0]:-2
Stack:4 Erzeuge neues int-Feld mit der Laenge: 1
Stack:5 Start doSomething
Rufe doSomethingOther auf feld.length:1 feld[0]:-5
Stack:6 Erzeuge neues int-Feld mit der Laenge: 0
Stack:7 Start doSomething
Stack:7 Return doSomething
Rufe doSomethingOther auf feld.length:1 feld[0]:-5
Stack:6 Erzeuge neues int-Feld mit der Laenge: 0
Stack:7 Start doSomething
Stack:7 Return doSomething
Rufe doSomethingOther auf feld.length:1 feld[0]:-5
Stack:6 Erzeuge neues int-Feld mit der Laenge: 0
Stack:7 Start doSomething
Stack:7 Return doSomething
Rufe doSomethingOther auf feld.length:1 feld[0]:-5
Stack:6 Erzeuge neues int-Feld mit der Laenge: 0
Stack:7 Start doSomething
Stack:7 Return doSomething
Rufe doSomethingOther auf feld.length:1 feld[0]:-5
Stack:6 Erzeuge neues int-Feld mit der Laenge: 0
Stack:7 Start doSomething
Stack:7 Return doSomething
Erstmal vielen lieben Dank. Ich verstehe alles bis auf den Schritt, wo das erste Mal nach "Stack:7 Return doSomething" wieder die doSomethingOther()-Methode aufgerufen wird. Diese "Stack:7..." Ausgabe konnte ja erst erfolgen, weil die while-Schleife nicht erfüllt war, damit die feld.length nicht mehr >0 ist und somit auch nirgends mehr der Aufruf nach doSomethingOther kommt.

Mir ist klar, ich hab irgendwo einen mächtigen Denkfehler aber ich bekomme ihn leider einfach nicht raus. Sorry...
 
Dein Denkfehler is die Annahme, dass Arrays in Java in ihrer Länge veränderbar seien.
Beim Hinundhergeben der Arrays sind ja die übergebenen Arrays immer kleiner bis es letztendlich eine Länge von 0 erreicht oder?
Das Anfangsarray feld = new int {1,2,3} ist doch schon nach der ersten Übergabe an doSomethingOther weg, da er nur zur LAufzeit der Methode existiert
 
Ich nehm gerne auch salopp ausgedrückte Antworten entgegen mit nicht genauer sprache :D Ich will das einfach nur in mein Kopf bekommen :(
 
Hä? Die Länge von Arrays ist nicht veränderbar. Drücke ich mich so missverständlich aus?
Das ist ja klar, aber mir gehts darum, dass wenn args als Argument an doSomething übergeben wird, wurde ja die Länge für die Methode verändert, da die vorherigen Anfangskomponenten ja nun gelöscht wurden wegen dem Laufzeitsgedöns...
Dass ein Array nicht seine Länge ändern kann, ist 100% klar, aber es geht mir darum welche Felder bleiben und welche gelöscht sind, nachdem eine andere MEthode aufgerufen wurde
 
Dass ein Array nicht seine Länge ändern kann, ist 100% klar, aber es geht mir darum welche Felder bleiben und welche gelöscht sind, nachdem eine andere MEthode aufgerufen wurde
Ich wiederhole mich:
feld wird nicht geändert. Folglich bleibt feld.length stets größer 0.
Am besten machst Du Dir das erstmal an zwei verschiedenen Methoden klar:

Java:
void a(String x) {
   b(x);
   System.out.println(x);
}
void b(String x) {
    x = "";
}
Was wird ausgegeben, wenn Du a("XYZ") aufrufst?
 
mihe, ich glaub der Lerneffekt ist gerade verpufft, weil Du die Frage falsch gestellt hast. :(
Er wollte ja keine tiefgreifende Erklärung und für den Zweck sollte es reichen :)

@SafeDebagger richtig. Du kann in b() also an das x zuweisen, was Du willst, das wirkt sich in a() nicht aus.

Wenn Du jetzt diesen Code nimmst:
Java:
    public static void doSomething(int[] feld) {
        while (feld.length > 0)
        doSomethingOther(feld);
    }
Dann kannst Du in doSomethingOther an feld zuweisen, was Du willst, es wird sich in doSomething() nicht auswirken. Die Variable feld ändert sich also nicht und da Arrays, wie @Tobias-nrw bereits erwähnt hat, in ihrer Länge nicht veränderbar sind, wird feld.length immer größer 0 bleiben (sofern es ursprünglich größer 0 war, versteht sich).
 
Sinn macht das erst, wenn etwas mehr über den Hintergrund bekannt ist :)

Ich versuche es mal wieder einfach: Java übergibt Parameter immer als Kopie (call by value) des zu übergebenden Werts. Bei primitiven Datentypen wie int etc. wird direkt der betreffende Wert kopiert. Bei Objekten dagegen wird nicht das Objekt selbst sondern nur eine Referenz (=Speicheradresse) darauf kopiert. In Java sind Arrays spezielle Objekte.

Daher kannst Du zwar eine übergebene Variable nicht ändern (die Zuweisung an x in b() wirkt sich nicht auf die übergebene Variable aus), aber - da das selbe(!) Objekt nur referenziert wird - wirken sich Änderungen am Objekt gleichermaßen aus.

Wichtig zu wissen ist noch, dass jeder Methodenaufruf separat behandelt wird, somit einen eigenen Satz an Parametern und lokalen Variablen erhält. Damit sollte auch klar werden, wie bzw. wieso rekursive Aufrufe funktionieren.
 
Passende Stellenanzeigen aus deiner Region:

Neue Themen

Oben