Kuriosität mit Inkrementierung
*Markus
- java
Hallo,
ich bin auf ein seltsames Problem gestoßen, das ich mir nicht erklären kann. Ich habe folgende Schleife bei der "Konten" mithilfe des übergebenen Index aus einer "KontoVerwaltung" gelöscht werden können:
public boolean loeschen(int index) {
if (index >= 0 && index < anzahl) {
int i = index;
while (i < anzahl) {
konten[i++] = konten[i+1];
}
konten[i] = null;
anzahl--;
return true;
}
return false;
}
Der Teil in der while-Schleife liefert eine NullPointerException aufgrund der Inkrementierung innerhalb der eckigen Klammern. Inkrementiere ich i außerhalb der Klammer, funktioniert es.
Kann sich das jemand erklären?
Komischerweise würde auch ++i funktionieren, woraufhin die Funktion aber ein verständlicherweise falsches Ergebnis liefert.
Markus.
Hi,
konten[i++] = konten[i+1];
Der Teil in der while-Schleife liefert eine NullPointerException aufgrund der Inkrementierung innerhalb der eckigen Klammern. Inkrementiere ich i außerhalb der Klammer, funktioniert es.
Kann sich das jemand erklären?
Gegenfrage: Was glaubst Du denn sei der Rückgabewert(!) von i++?
Komischerweise würde auch ++i funktionieren,
Und was gibt im Gegensatz dazu ++i zurück?
Cheatah
Hallo,
Gegenfrage: Was glaubst Du denn sei der Rückgabewert(!) von i++?
Wie meinst du das mit dem Rückgabewert? Meiner Logik zufolge müsste doch
konten[i++] = konten[i+1] bewirken, dass zuerst die nächst höhere Referenz konten[i] zugewiesen wird, und dann i inkrementiert wird. Ich bilde mir ein, in Perl würde das so funktionieren.
Und was gibt im Gegensatz dazu ++i zurück?
++i bewirkt, dass genau jenes Konto gelöscht wird, das sich eine Position "oberhalb" des übergebenen Index befindet.
Markus.
gudn tach!
[...] müsste doch
konten[i++] = konten[i+1] bewirken, dass zuerst die nächst höhere Referenz konten[i] zugewiesen wird, und dann i inkrementiert wird. Ich bilde mir ein, in Perl würde das so funktionieren.
ja, und den anderen sprachen mit c-syntax ebenfalls.
prost
seth
Hallo,
ja, und den anderen sprachen mit c-syntax ebenfalls.
Das heißt also, dass es eine Java-Eigenheit ist, und kein logischer Fehler?
Markus.
gudn tach!
ja, und den anderen sprachen mit c-syntax ebenfalls.
Das heißt also, dass es eine Java-Eigenheit ist, und kein logischer Fehler?
nein, java zaehle ich zu den sprachen mit c-syntax.
dein fehler liegt, wie in diesem posting bereits angedeutet, wahrscheinlich an dem zugriff auf konten[anzahl].
ich wuerde es so
while (i<anzahl-1)
konten[i++] = konten[i+1];
oder so
for(int i=index; i<anzahl-1; ++i)
konten[i] = konten[i+1];
konten[--anzahl] = null;
schreiben.
wobei das noch ausser acht laesst, dass es fuer sowas bessere datenstrukturen gibt (hat Richard ja in https://forum.selfhtml.org/?t=129973&m=840415 auch schon angesprochen).
prost
seth
Hallo,
dein fehler liegt, wie in diesem posting bereits angedeutet, wahrscheinlich an dem zugriff auf konten[anzahl].
Also nach langem Herumtesten und Fehler ausmerzen kam ich zwar drauf, dass es while (j+1 < anzahl) heißen muss, damit bei einer vollen Kontoverwaltung kein OutOfBoundsException entsteht, aber nichts desto trotz funktioniert i++ innerhalb der eckigen Klammern nicht.
Es ist mir unbegreiflich, da i++ außerhalb und innerhalb eigentlich in der Gesamtheit der Schleife identisch sind.
Markus.
gudn tach!
nichts desto trotz funktioniert i++ innerhalb der eckigen Klammern nicht.
oops, du hattest eben mit der vermutung recht. java macht es doch anders als c++.
habe auch einen langer thread ueber das thema in einem anderen forum gefunden (aber nicht alles gelesen).
nun java macht es also anders.
code:
konten[i++] = konten[i+1];
ist in c++:
konten[i] = konten[i+1]; ++i;
und in java:
konten[i] = konten[++i+1];
c++ wartet auf das ende der gesamten anweisung vor dem inkrementieren und java inkrementiert sofort nach dem teilausdruck.
wenn du also
konten[i] = konten[i++ +1];
schreiben wuerdest, funzt auch in java.
prost
seth
Hallo,
c++ wartet auf das ende der gesamten anweisung vor dem inkrementieren und java inkrementiert sofort nach dem teilausdruck.
Alles klar, das würde das Verhalten meiner Methode erklären. :)
wenn du also
konten[i] = konten[i++ +1];
schreiben wuerdest, funzt auch in java.
Das sind natürlich Konstrukte, die man eher meiden sollte, wovon mich mein Lehrer auch schon immer warnte :)
Markus.
Hi,
Gegenfrage: Was glaubst Du denn sei der Rückgabewert(!) von i++?
Wie meinst du das mit dem Rückgabewert?
damit meine ich, dass jede Operation - egal ob Aufruf einer Methode, Abgreifen eines Variablenwertes, Durchführen einer Inkrementierung oder was auch immer - in ihren Kontext eine Rückgabe liefert. Wie lautet die Rückgabe der Operation "i++"?
Meiner Logik zufolge müsste doch konten[i++] = konten[i+1] bewirken,
Was es bewirkt ist egal. Was liefert i++ zurück? Was liefert i+1 zurück? Was liefert ++i zurück?
[...] und dann i inkrementiert wird.
Der Einfluss auf i hat mit dieser meiner Frage übrigens nichts zu tun.
Cheatah
Hallo,
Was es bewirkt ist egal. Was liefert i++ zurück? Was liefert i+1 zurück? Was liefert ++i zurück?
Es liefert WAHR zurück. Es wäre mir angenehm, wenn du mich nicht herumraten lassen würdest, sondern mir konkret sagen könntest, warum das so nicht funktioniert.
Ich habe die kompletten Beispiele mal hier hochgeladen:
http://test.pithax.net/Konto.java
http://test.pithax.net/KontoVerwaltung.java
Markus.
Hi,
Was liefert i++ zurück? Was liefert i+1 zurück? Was liefert ++i zurück?
Es liefert WAHR zurück.
auf welche meiner drei Fragen ist das die Antwort? Und was genau steht in konten[WAHR]?
Es wäre mir angenehm, wenn du mich nicht herumraten lassen würdest, sondern mir konkret sagen könntest, warum das so nicht funktioniert.
Nein, ich lasse Dich lieber nachdenken, wie man einem Problem auf die Spur kommt. Davon haben wir beide und eventuelle Mit- und Nachleser nämlich sehr viel mehr.
Cheatah
gudn tach!
ich lasse Dich lieber nachdenken, wie man einem Problem auf die Spur kommt. Davon haben wir beide und eventuelle Mit- und Nachleser nämlich sehr viel mehr.
ich fand aber innerhalb dieses threads deine beitraege nicht hilfreich[1]. und selbst jetzt, wo ich die java-funktionsweise diesbzgl. kenne, weiss ich immer noch nicht, ob du wirklich auf dasselbe hinauswolltest.
prost
seth
[1] ich bewerte sie jedoch nicht als "nicht hilfreich", weil ich eher vermute, dass ich mich einfach bloss beim verstehen zu doof anstelle.
Hallo,
Nein, ich lasse Dich lieber nachdenken, wie man einem Problem auf die Spur kommt. Davon haben wir beide und eventuelle Mit- und Nachleser nämlich sehr viel mehr.
Das finde ich absolut nicht. Warum glaubst du zu wissen, was für mich oder andere am besten ist? Dieses Herumraten meinerseits erscheint mir für viele nicht sehr hilfreich zu sein, da sich sämtliche Mitleser erst durch dutzende Postings, durch mein Raten verursacht, wühlen müssen, um folgen zu können. Manche lernen nur dann gut, wenn sie im Zimmer auf- und abgehen. Andere können nur hinterm Schreibtisch lernen.
Ich wiederum, wie wahrscheinlich viele andere Leute, lerne am besten anhand von vielen Beispielen. Du denkst vielleicht, dass man auf diese Weise schnell dazu verleitet wird, sich die Lösung zu jedem noch so kleinen Problem von den anderen vorkauen lässt und denkfaul wird, was sicher oft zutrifft.
Ich kann mich aber nicht erinnern, je eine Frage hier gestellt zu haben, die ich mir ein paar Minuten später vielleicht hätte selbst beantworten können.
Markus.
Hallo,
Ich glaube, du wendest den Inkrementationsoperator ganz einfach falsch an. i wird innerhalb der eckigen Klammern, und nirgendwo anders, hochgezählt. Beim nächsten while-Durchlauf ist es wieder i und nicht i+1.
Viele Grüße
Hallo,
Ich glaube, du wendest den Inkrementationsoperator ganz einfach falsch an. i wird innerhalb der eckigen Klammern, und nirgendwo anders, hochgezählt. Beim nächsten while-Durchlauf ist es wieder i und nicht i+1.
i wurde außerhalb der Schleife definiert wodurch es seinen Wert innerhalb der Schleife nicht einfach so wieder verlieren kann.
Markus.
Hallo,
i wurde außerhalb der Schleife definiert wodurch es seinen Wert innerhalb der Schleife nicht einfach so wieder verlieren kann.
Um die Schleife aber überhaupt schleifen zu lassen, muss i selbst inkrementiert werden:
while(i < anzahl) {
kosten[i] = 100;
i++;
}
Viele Grüße
Hello out there!
Um die Schleife aber überhaupt schleifen zu lassen, muss i selbst inkrementiert werden
Wird es doch.
Der Unterschied von
while(i < anzahl) {
kosten[i] = 100;
i++;
}
zu
while(i < anzahl) {
kosten[i++] = 100;
}
bzw.
while(i < anzahl) {
kosten[++i] = 100;
}
wäre welcher?
See ya up the road,
Gunnar
Hallo,
OK, jetzt hab ich nochmal nachgelesen.
BTW:
@*Markus: Für dynamische Datenstrukturen bieten sich doch anstelle von simplen Arrays eher ArrayLists oder HashMaps an, oder nicht? Durch die kann man bequem durch-iterieren und an gewünschter Stelle removen.
Viele Grüße
gudn tach!
Der Unterschied von
while(i < anzahl) {
kosten[i] = 100;
i++;
}
>
> zu
>
> ~~~java
while(i < anzahl) {
> kosten[i++] = 100;
> }
bzw.
while(i < anzahl) {
kosten[++i] = 100;
}
>
> wäre welcher?
hmmpf, ich hatte hierauf eben schon mal geantwortet, aber mal wieder vergessen, nach der vorschau noch mal auf absenden zu klicken.
naja, war eh nur ein verlinkter hinweis auf die loesung.
und da Richard jetzt eh bescheid weiss, sag ich's halt dem archiv:
beispiel 1 und 2 sind aequivalent, beispiel 3 macht was anderes. das erklaeren einem sehr viele seiten im internet, sogar auf deutsch; stichwort: "inkrementierungsoperator".
prost
seth
gudn tach!
while (i < anzahl) {
^^^^^^^^
konten[i++] = konten[i+1];
^^^
wobei ich hier nur rate, was anzahl ist.
prost
seth
Hallo *Markus,
Der Teil in der while-Schleife liefert eine NullPointerException aufgrund der Inkrementierung innerhalb der eckigen Klammern.
Das dürfte eine ArrayIndexOutOfBounds-Exception sein. Eine NullPointerException könnte höchstens dann auftreten, wenn konten = null wäre.
Der nächste Punkt:
konten[i++] = konten[i+1];
Hier hab' ich erst mal überlegt, ob eigentlich zuerst die rechte Seite der Zuweisung oder i++ ausgewertet wird. Ziehe das i++ da lieber raus oder in den Kopf einer for-Schleife. Solche Trickserreien verwirren nur und bringen nichts.
Was bereits schon angedeutet wurde: Warum versuchst Du Dir selber so eine Krücke zu basteln, wenn Java fertige, ausgereifte Datenstrukturen mitbringt? Geeignet wäre z.B. ArrayList. Der einzige Grund, in so einem Fall direkt mit Arrays rumzubasteln, wäre, dass es sich um eine Übungsaufgabe handelt oder dass man aus Performancegründen o.ä. eine sehr genaue Kontrolle darüber will, wann neue Arrays angelegt und Daten zwischen Arrays kopiert werden.
Grüße
Daniel
Hallo,
Was bereits schon angedeutet wurde: Warum versuchst Du Dir selber so eine Krücke zu basteln, wenn Java fertige, ausgereifte Datenstrukturen mitbringt?
Ich weiß schon, auch dank der Hinweise hier, dass es einfach ginge, aber mir ging es hauptsächlich nur um das Verständnis dahinter, da ich gerne ausprobiere was in den verschiedenen Sprachen so alles funktionert.
Markus.
gudn tach!
while (i < anzahl) {
hier war ja schon der erste fehler.
konten[i++] = konten[i+1];
und hier ist in java der zweite. in c++ waer's richtig.
warum ich jetzt trotz der anderen postings mich noch mal melde:
ich hab's jetzt auch im manual gefunden:
15.7.2 Evaluate Operands before Operation
in java also
konten[i++] = konten[i];
oder
konten[i] = konten[i++ +1];
oder gleich
konten[i] = konten[++i];
prost
seth
Hallo seth,
Eigentlich ist 15.7.1 Evaluate Left-Hand Operand First relevant oder wem das noch zu unspezifisch ist 15.26.1 Simple Assignment Operator =.
In diesem Abschnitt steht explizit, dass der Unterausdruck einer Arrayreferenz zuerst ausgewertet wird.
Deine Folgerungen daraus sind allerdings richtig. Die Tatsache, dass man, um den Code zu verstehen und zu korrigieren erst einmal die Sprachspezifikation im Detail lesen muss, bestätigt mich allerdings darin, dass man das so nicht machen sollte.
Grüße
Daniel