Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Schleifenzähler um eins heruntersetzen
Pow - Do 22.07.10 12:56
Titel: Schleifenzähler um eins heruntersetzen
Hallo,
ist es möglich bei einer for-Schleife den Zähler unter einer bestimmten Bedingung heruntersetzen zu lassen?
Ich gehe nämlich in einer for-Schleife in eine repeat-until-Schleife und wenn dort z.B. die Variable "Vorgang_abbrechen" durch einen Button gesetzt wird,
soll er durch continue von vorne anfangen, aber nicht den Zähler hochzählen, sondern den gleichen Durchlauf beginnen
Kann man sowas realisieren?
z.B.:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| for ii := 1 to [..] do begin if Vorgang_abbrechen = true then begin ii := ii - 1; end; Vorgang_abbrechen := false;
repeat [..] until Vorgang_abbrechen or [..]; if Auftrag_unterbrechen then begin break; end else if Vorgang_abbrechen then begin continue; end; |
Moderiert von
Narses: Topic aus Sonstiges (Delphi) verschoben am Do 22.07.2010 um 13:02
elundril - Do 22.07.10 12:59
Ja, irgendwo hat im DF das einer mal reingehackt über Pointer usw, glaub ich. Aber prinzipiell: Nein, das is böse und wird aus gutem Grund vom Complier verboten. Aber wenn es dir hilft: Aus jeder for-Schleife kann man eine repeat-until oder while-Schleife machen. ;)
lg elundril
Pow - Do 22.07.10 13:11
Oh.. ja richtig, danke für den Hinweis :)
Mit einer while-Schleife funktionierts natürlich
spawn89 - Do 22.07.10 13:14
Ansonsten noch zur Vollständigkeit bzw zu Lernzwecken:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| var i: Integer; begin for i := 1 to 1 do begin Integer(Pointer(@i)^) := i-1; ShowMessage('Aufruf Nr.: '+IntToStr(i)); end; end; |
thepaine91 - Do 22.07.10 13:16
So gehts auch ist aber letzendlich mehr oder weniger das selbe.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure TForm1.Button1Click(Sender: TObject); var pt: ^integer; i: integer; begin for i := 0 to 99 do begin pt := @i; pt^ := 99; ShowMessage(inttostr(i)); end; end; |
Nersgatt - Do 22.07.10 15:50
Wobei ich mich definitv dafür ausspreche, dass jeder, der solche Spielchen in produktivem Quellcode einbaut, geteert und gefedert wird. Außerdem wird ihm der PC entzogen und er darf bis ans Lebensende nur noch Basic auf einem VC20 programmieren :D
Was ich sagen will: Nimm ne While-Schleife und verwalte den Zähler komplett selbst. :D
glotzer - Do 22.07.10 16:20
dumme frage, aber was ist so böse dran?
elundril - Do 22.07.10 17:42
Wurde damals in dem von mir erwähnten unbekannten Thread erklärt warum das schlecht ist, bitte zwing mich nicht ihn rauszusuchen. Ich hab nämlich keine Ahnung von wem der Beitrag war und welche Stichworte auf den Thread passen würden.
lg elundril
yogo - Do 22.07.10 18:14
Ist es nicht so, dass bei eingaschalteter optimierung schleifen insgeheim von hinten nach vorne gehen? (von 50 -> 1)
macht ja auch sinn, dann brauch man nur ein register mit dec zu verringern und nicht noch ein etra register für den vergleich nach eine subtraktion.
dec und jz
dann wäre der vermeintliche schritt nach hinten ein schritt nach vorne, oder lieg ich falsch?
Narses - Do 22.07.10 22:02
Moin!
Der Compiler optimiert die Laufvariable nur dann, wenn du nicht darauf zugreifst. Wird die Laufvariable im Schleifenkörper verwendet, werden auch genau die bei den Grenzen angegebenen Werte erzeugt.
Allerdings zwingt man den Compiler auf diese Weise eine Register-Optimierung zu unterlassen (wenn ich das richtig verstanden habe, aber das kann
BenBE sicher besser erklären ;)).
Togal: es ist und bleibt schlechter Stil, weil es den Code weniger wartungsfreundlich und undurchsichtiger macht. Normalerweise rechnet man nicht damit, dass in einer for-Schleife die Laufvariable im Körper verändert wird.
IMHO ist es grade noch tolerierbar, eine for-Schleife zu verlassen, z.B. die klassische IndexOf-Methode:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| function IndexOf(const Needle: String; Haystack: TStrings): Integer; begin for Result := 0 to Haystack.Count-1 do if (Haystack[Result] = Needle) then Exit; Result := -1; end; |
Hier wird die Schleife lediglich abgebrochen - performant und trotzdem intuitiver Code. :idea: Grundsätzlich würde ich immer davon abraten, schreibend auf die Laufvariable zuzugreifen.
cu
Narses
//EDIT: Redaktionelle Änderungen nach
alzaimars Hinweisen.
Nersgatt - Fr 23.07.10 07:12
Narses hat folgendes geschrieben : |
IMHO ist eine der wenigen Ausnahmen die klassische IndexOf-Methode:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7:
| function IndexOf(const Needle: String; Haystack: TStrings): Integer; begin for Result := 0 to Haystack.Count-1 do if (Haystack[Result] = Needle) then Exit; Result := -1; end; | |
Sowas mache ich persönlich immer mit einer While-Schleife:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| function IndexOf(const Needle: String; Haystack: TStrings): Integer; var i : Integer; begin i := 0; Result := -1; while (i <= Haystack.Count - 1) and (result = -1) do begin if (Haystack[i] = Needle) then Result := i; inc(i); end; end; |
So sieht man schon am Schleifenkopf, zu welchen Bedingungen die Schleife terminieren wird und stößt nicht überraschenderweise auf ein Exit mitten im Schleifenkörper.
Jens
spawn89 - Fr 23.07.10 07:53
Break; und Exit; nutze ich auch sehr aktiv und das nicht ohne Grund.
Wenn ich wirklich so die Abfragen wie Nersgatt einbaun würde hätte ich oftmals zeilenlange Bedingungen, durch die später keiner mehr durchblickt.
Oder man müsste Bedingungen in weitere Unterfunktionen kapseln. :roll:
alzaimar - Fr 23.07.10 08:22
Narses hat folgendes geschrieben : |
... rechnet man nicht damit, dass in einer for-Schleife die Laufvariable im Körper verändert wird.
... IMHO ist eine der wenigen Ausnahmen die klassische IndexOf-Methode:... |
Wo wird denn in der IndexOf-Methode die Laufvariable verändert? :gruebel:
Narses hat folgendes geschrieben : |
...Grundsätzlich würde ich immer davon abraten, die Laufvariable anzufassen. |
Wieso? Dann würdest Du ja jeden Array-Scan über eine WHILE-Schleife realisieren? Du meinst sicherlich "schreibend zugreifen".
Nersgatt hat folgendes geschrieben : |
Sowas mache ich persönlich immer mit einer While-Schleife:... |
Wieso einfach, wenns auch umständlich geht.
Nersgatt hat folgendes geschrieben : |
So sieht man schon am Schleifenkopf, zu welchen Bedingungen die Schleife terminieren wird und stößt nicht überraschenderweise auf ein Exit mitten im Schleifenkörper. |
Klar. Übersichtlicher gehts nicht. Was macht die Schleife nochmal? Ach ja.
"Solange i noch nicht am Ende ist und ein Resultat = -1 ist, soll was gemacht werden?.. ach und wenn dann die Nadel gefunden wurde, wird das Resultat auf die Laufvariable gesetzt und die wird dann erhöht. ... Aha.. Ach soooo.. und dann hört die While-Schleife ja auf, weil das Resultat nicht mehr -1 ist. Toller Trick." Tricks haben im Code nix zu suchen. :lol:
Hmm. Das ist mir Folgendes wirklich lieber: "Suche im Heuhaufen, bis Du die Nadel gefunden hast und hör dann auf zu suchen."
Das wäre die deutsche Übersetzung der For-Schleife, wobei der letzte Teil das 'überraschende Stoßen auf das EXIT' darstellt.
So ein "EXIT" ist aber höchstens so überraschend ("Huch!") wie ein 'inc(i)' oder ein nicht für möglich gehaltenes 'IF'.
thepaine91 - Fr 23.07.10 09:26
Ich bin für diese Variante:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| function TForm1.IndexOf(const Needle, Haystack: Pointer): Integer; var sref: ^string; tsref: ^TStrings; label lbl; begin sref := Needle; tsref := Haystack; for Result := 0 to tsref^.Count - 1 do begin if tsref^[Result] = sref^ then goto lbl; end; lbl: end; |
Narses - Fr 23.07.10 09:33
Moin!
alzaimar hat folgendes geschrieben : |
Narses hat folgendes geschrieben : | ... rechnet man nicht damit, dass in einer for-Schleife die Laufvariable im Körper verändert wird.
... IMHO ist eine der wenigen Ausnahmen die klassische IndexOf-Methode:... | Wo wird denn in der IndexOf-Methode die Laufvariable verändert? :gruebel: |
Dämlich zusammengestellt, zugegeben. :nixweiss:
alzaimar hat folgendes geschrieben : |
Narses hat folgendes geschrieben : | ...Grundsätzlich würde ich immer davon abraten, die Laufvariable anzufassen. | Wieso? Dann würdest Du ja jeden Array-Scan über eine WHILE-Schleife realisieren? Du meinst sicherlich "schreibend zugreifen". |
Ja, selbstverständlich, danke für die Korrektur. :flehan:
cu
Narses
spawn89 - Fr 23.07.10 09:36
thepaine91 hat folgendes geschrieben : |
Ich bin für diese Variante:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| function TForm1.IndexOf(const Needle, Haystack: Pointer): Integer; var sref: ^string; tsref: ^TStrings; label lbl; begin sref := Needle; tsref := Haystack; for Result := 0 to tsref^.Count - 1 do begin if tsref^[Result] = sref^ then goto lbl; end; lbl: end; | |
Da sieht man mal wieder, kaum kommen mehr unnötige Zeilen dazu sind Fehler drin.
thepaine91 - Fr 23.07.10 09:39
Das funktioniert hab es vorher getestet.
spawn89 - Fr 23.07.10 09:42
Überleg mal was passiert wenn der string nicht enthalten ist.
Tja, das sieht man nicht mehr auf anhieb, da es mittlerweile schon an Code 'überquillt'.
btw: Kommt da nicht eine Compiler-Warnung?
thepaine91 - Fr 23.07.10 09:54
So ist es besser und hast recht ^^ das hab ich wirklich nicht bedacht ;)
So kommt keine Meldung mehr vorher kam nur Result könnte undefiniert sein.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| function TForm1.IndexOf(const Needle, Haystack: Pointer): Integer; label lbl; begin for Result := 0 to TStrings(Haystack^).Count - 1 do begin if Tstrings(Haystack^)[Result] = string(Needle^) then goto lbl; end; Result := -1; lbl: end; |
Jakob_Ullmann - Fr 23.07.10 11:07
was haltet ihr davon:
Delphi-Quelltext
1: 2: 3: 4: 5:
| for i := 1 to 20 do if i = 12 then asm dec i end; |
jaenicke - Sa 24.07.10 08:55
Narses hat folgendes geschrieben : |
IMHO ist eine der wenigen Ausnahmen die klassische IndexOf-Methode:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7:
| function IndexOf(const Needle: String; Haystack: TStrings): Integer; begin for Result := 0 to Haystack.Count-1 do if (Haystack[Result] = Needle) then Exit; Result := -1; end; | |
Wobei genau genommen der Wert der Schleifenvariablen nach der Schleife nicht definiert ist. Dass hier vermutlich keine Compilerwarnung kommt, liegt schlicht daran, dass nicht mehr lesend auf Result zugegriffen wird.
Und dass Delphi da nicht aufräumt, liegt daran, dass Result in EAX liegt und EAX als Ergebnisregister nicht aufgeräumt werden muss. Deshalb klappt es, aber theoretisch kann sich die Implementierung von Schleifen auch ändern.
Nersgatt hat folgendes geschrieben : |
Sowas mache ich persönlich immer mit einer While-Schleife: |
Also wenn du schon auf die Lesbarkeit und Wartbarkeit anspielst, dann solltest du es nicht noch extra kryptisch machen... Dann lieber richtig:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| function IndexOf(const Needle: String; Haystack: TStrings): Integer; var i: Integer; Found: Boolean; begin i := 0; Found := False; while (i <= Haystack.Count - 1) and not Found do begin Found := Haystack[i] = Needle; if not Found then Inc(i); end; if Found then Result := i else Result := -1; end; |
Letztlich finde ich es viel wichtiger, dass man den Quelltext ordentlich formatiert (ich hasse es, wenn jemand das Exit oder andere Befehle irgendwo hinten in der Zeile versteckt... :autsch:) und sprechende Bezeichner wählt. Dann überblickt jeder gute Programmierer auch die Variante mit Exit gut.
Ich selbst mache
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!