Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   For in For dann Goto (https://www.delphipraxis.net/159138-dann-goto.html)

demic 15. Mär 2011 21:46

Delphi-Version: 5

For in For dann Goto
 
Hallo,

habe einen Code der funktioniert.

Als Beispiel:

Delphi-Quellcode:
procedure...
label ForEnd;
begin
 for a := 0 to 10 do
 begin
  for b := 0 to 20 do
  begin
   if prüfungsachen u.a. mit 'a' und 'b' then Goto ForEnd;
  end;
 end;
 ForEnd:
 ... variable a und b für die weitere Verarbeitung
end;
Delphi gibt hier Warnungen aus:
For Schleifenvariable 'a' kann nach Durchlauf undefiniert sein
For Schleifenvariable 'b' kann nach Durchlauf undefiniert sein

Versteh ich nur halbwegs... z.b. wenn ein Goto vor der FOR-Schleife stattfinden sollte. Das ist jetzt nicht der Fall. Habe nun mal die Hilfe gelesen.

Da steht folgendes:
Diese Warnung wird angezeigt, wenn die Steuervariable einer for-Schleife nach der Schleife verwendet wird.
Sie können sich nur auf den letzten Wert eines for-Schleifenzählers verlassen, wenn die Schleife mit einer goto- oder exit-Anweisung verlassen wird.
Der Grund für diese Einschränkung ist, dass der Compiler dadurch sehr effizienten Code für die for-Schleife erzeugen kann.

Je nach Prüfung verlässt Goto die beiden FOR-Schleifen korrekt und in 'a' und 'b' habe ich die richtigen Werte. Ich lese jedoch in der Hilfe, dass ich mich eigentlich nur darauf verlassen kann, dass in 'a' der Wert 10 und in 'b' der Wert 20 stehen kann.

Verstehe ich etwas falsch?

Gruß
Michael

Medium 15. Mär 2011 21:55

AW: For in For dann Goto
 
Das Problem hier ist, dass die Schleife ggf. komplett durchlaufen kann, und dann ja trotzdem der Code unter deinem ForEnd Label ausgeführt wird. In diesem Falle wären dann a und b undefiniert. Lösung: Nutze ein weiteres Label, dass im unmittelbar nach der Schleife angesprungen wird, also wenn die "prüfungssachen mit a und b" nie zutreffen. Alternativ muss man natürlich empfehlen, das Konzept an der Stelle komplett zu überdenken, da Gotos allgemein zu miserablem Stil zählen ;)

Edit: Mit den [ delphi] ... [ /delphi] Tags (ohne Leerzeichen) schaut der Code hier im Forum auch hübsch aus, Beispiel:
Delphi-Quellcode:
procedure...
label ForEnd, ForNothing;
begin
 for a := 0 to 10 do
 begin
  for b := 0 to 20 do
  begin
   if prüfungsachen u.a. mit 'a' und 'b' then Goto ForEnd;
  end;
 end;
 Goto ForNothing;
 ForEnd:
 ... variable a und b für die weitere Verarbeitung
 ForNothing:
end;

alfold 15. Mär 2011 22:19

AW: For in For dann Goto
 
Holla, sehe ich da ein Goto?
LOL, gibts das in Delphi? Wo benutz man den dieses noch?
Ausser in diesem Beispiel.

alfold

Medium 15. Mär 2011 22:22

AW: For in For dann Goto
 
Streng genommen halt garnicht :mrgreen:

BUG 15. Mär 2011 22:53

AW: For in For dann Goto
 
Zitat:

Zitat von alfold (Beitrag 1088837)
Wo benutz man den dieses noch?
Ausser in diesem Beispiel.

Sonst nicht :mrgreen:
Der Ausbruch aus mehreren verschachtelten Schleifen ist eine der wenigen Gelegenheiten in denen man es eventuell akzeptieren kann.

Wurde schon oft diskutiert: Hier im Forum suchenGOTO



Im Prinzip ist die Zählervariable außerhalb der for-Schleife undefiniert, aber anscheinend wird der aktuelle Wert garantiert, wenn man mit exit oder goto aus der Schleife springt.

Eine andere Variante, die keine Warnungen bringen sollte:
Delphi-Quellcode:
procedure tuWas;
label ForEnd;
begin
  for a := 0 to 10 do
  begin
    for b := 0 to 20 do
    begin
      if prüfungsachen u.a. mit 'a' und 'b' then Goto ForEnd;
    end;
  end;
  // Wenn nicht herausgesprungen,
  // setze die Zählervariablen auf Endwerte.
  a := 10;
  b := 20;
  ForEnd:
  //... variable a und b für die weitere Verarbeitung
end;
Beide Varianten machen etwas anderes.

PS: Mediums Variante geht mit exit (dem kleinen Bruder von goto) allerdings auch:
Delphi-Quellcode:
procedure tuWas;
begin
  for a := 0 to 10 do
  begin
    for b := 0 to 20 do
    begin
      if prüfungsachen u.a. mit 'a' und 'b' then
      begin
        //... variable a und b für die weitere Verarbeitung
        exit; // Achtung: springe aus der ganzen Prozedur
      end;
    end;
  end;
end;

Medium 15. Mär 2011 23:08

AW: For in For dann Goto
 
Daaaa haste völlig Recht, so wäre es noch netter. Exit sehe ich auch bei weitem als nicht ganz so fies an, nicht zuletzt, weil ich aus C-likes mit "return foo;" ein "result := foo; Exit;"-Konstrukt mittlerweile gewöhnt bin und zu schätzen gelernt habe. Das war auch grob, was ich mit "Konzept überdenken" gemeint hatte: Den Schleifenteil in eine Methode auslagern, die im frühen Erfolgsfall mit dem Ergebnis zurück kehrt. (Schaut mir nämlich arg nach einem (bi-)liniearen Suchvorgang aus, wo so was klassisch ist.)

alfold 15. Mär 2011 23:20

AW: For in For dann Goto
 
Währe in seinem Beispiel nicht Break besser als goto?
Exit bedeutet doch das ich die Procedure vorzeitig verlasse.
Break, ich unterbreche die Schleife.

Oder verwirrt mich jetzt das goto :shock:


€ alles zurück habs verstanden 8-)
musste es 2 mal lesen
alfold

divBy0 15. Mär 2011 23:25

AW: For in For dann Goto
 
Steht doch im Kommentar, Exit verlässt die gesamt Prozedur.

Oder was meinst du?

alfold 15. Mär 2011 23:29

AW: For in For dann Goto
 
Nee alles ok :mrgreen:
War noch mit den Gedanken bei der Diskusion über GOTO:duck:

alfold

himitsu 15. Mär 2011 23:37

AW: For in For dann Goto
 
Delphi-Quellcode:
procedure...
label ForEnd;
begin
  for a := 0 to 10 do
  begin
    for b := 0 to 20 do
    begin
      if ... then
        Goto ForEnd;
    end;
  end;
  ForEnd:
  ...
end;
dieses läßt sich so behandeln
Delphi-Quellcode:
procedure...
label ForEnd;
begin
  try
    for a := 0 to 10 do
    begin
      for b := 0 to 20 do
      begin
        if ... then
          Exit;
      end;
    end;
  finally
    ...
  end;
end;
ABER
Zitat:

variable a und b für die weitere Verarbeitung
auf die Schleifenwerte von A und B darf außerhalb der jeweiligen FOR-Schleifen nicht zugegriffen werden,
also liegt hier eh ein gravierender Logikfehler vor :!:

Man kann diese Variablen zwar wiederverwenden, aber nach den Schleifen sind deren werte erstmal "undefiniert", weswegen sie bei einer Wiederverwendung notfalls nochmal initialisiert werden müssen.
So oder so, nach dem Exit darf auf diese Schleifen-Variablen nicht nochmal lesend zugegriffen werden.

Die einzige Lösung wären also Repeat- oder While-Schleifen.




Und ja, Goto hat teilweise auch seine Berechtigung.
Von mir schwirrt sogar ein Code damit in der CodeLib rum, welcher sich anders hätte wesentlich umständlicher lösen lassen :angle2:

BUG 16. Mär 2011 00:00

AW: For in For dann Goto
 
Himtisu macht die Verwirrung wieder komplett :lol:

Luckie 16. Mär 2011 05:07

AW: For in For dann Goto
 
Und ich hoffe, das führt dazu, dass von GOTO Abstand genommen wird. :roll:

alzaimar 16. Mär 2011 05:58

AW: For in For dann Goto
 
Vor allen Dingen und zuerst sollte davon Abstand genommen werden, Schleifenvariablen außerhalb der Schleife benutzen zu wollen.

GOTO ist nicht böse, aber die Sache mit den Schleifenvariablen schon!

GOTO ist nur häßlich.

vergessen 16. Mär 2011 06:33

AW: For in For dann Goto
 
Delphi-Quellcode:
procedure...
label ForEnd;
begin
a:=0;
b:=0;
for a := 0 to 10 do
begin
for b := 0 to 20 do
begin
if prüfungsachen u.a. mit 'a' und 'b' then Goto ForEnd;
end;
end;
ForEnd:
... variable a und b für die weitere Verarbeitung
end;
oder ohne goto

Delphi-Quellcode:
procedure...
begin
a:=0;
b:=0;
for a := 0 to 10 do
begin
for b := 0 to 20 do
begin
if prüfungsachen u.a. mit 'a' und 'b' then break;
end;
end;
... variable a und b für die weitere Verarbeitung
end;
sollte funktionieren.

mkinzler 16. Mär 2011 06:50

AW: For in For dann Goto
 
Oder mit einem else-Zweig

himitsu 16. Mär 2011 08:07

AW: For in For dann Goto
 
@vergessen: Break und Continue funktionieren nur durch eine Schleifenebene hindurch ... hier sind es aber 2 Ebenen.

Wenn, dann müßte jeweils ein Break pro Schleife rein

Delphi-Quellcode:
for a := 0 to 10 do
begin
  for b := 0 to 20 do
  begin
    ...
    if ... then Break;
  end;
  if ... then Break;
end;
Wie gesagt, While/Repeat-Schleifen wären die einzig wirklich praktikable Lösung, vorallem da nach diesen die (Schleifen)-Variablen noch verfügbar wären. (es sind dann ja keine "echten" Schleifenvariablen mehr :angle2: )

Wenn man es schlau anstellt, dann kann man diese beiden einfachen Schleifen auch auf eine Schleife runterschrumpfen und schon geht Break wieder voll durch. :mrgreen:


wie wäre es so?
Delphi-Quellcode:
a := -1;
repeat
  Inc(a);
  b := -1;
  repeat
    Inc(b);
    ...
    Abbrechen := not {prüfungsachen u.a. mit 'a' und 'b'};
  until Abbrechen or (b >= 20);
until Abbrechen or (a >= 10);
...
ShowMessage(Format('a = %d und b = %d', [a, b]));

// oder

a := -1;
repeat
  Inc(a);
  b := -1;
  repeat
    Inc(b);
    Abbrechen := not {prüfungsachen u.a. mit 'a' und 'b'};
    if Abbrechen then Break;
    ...
  until Abbrechen or (b >= 20);
until Abbrechen or (a >= 10);
...
ShowMessage(Format('a = %d und b = %d', [a, b]));

vergessen 16. Mär 2011 08:14

AW: For in For dann Goto
 
@himitsu, schon klar, aber dem TE geht es wohl um

zitat
Delphi gibt hier Warnungen aus:
For Schleifenvariable 'a' kann nach Durchlauf undefiniert sein
For Schleifenvariable 'b' kann nach Durchlauf undefiniert sein

dachte ich.

Daher sollte ein
Delphi-Quellcode:
a:=0;
b:=0;
vor den Schleifen reichen.

Blup 16. Mär 2011 08:21

AW: For in For dann Goto
 
Der Zugriff auf for-Schleifenvariablen nach Verlassen der Schleife ist in erster Linie deshalb unzulässig, weil der Compiler bei eingeschalteter Optimierung so etwas daraus macht:
Delphi-Quellcode:
for a := 10 downto 0 do
begin
  for b := 20 downto 0 do
  begin
    if prüfungsachen u.a. mit '10 - a' und '20 - b' then break;
  end;
end;

himitsu 16. Mär 2011 08:21

AW: For in For dann Goto
 
Warum sollte es reichen?

Diese Variableninhalte sind nach der Schleife undeffiniert.
Davor Zu Beginn wird es von Delphi automatisch initialisiert.
(nämlich mit dem Wert nach dem
Delphi-Quellcode:
:=
des For-To/Downto-Do)
Und wie grade erwähnt, optimiert der Compiler deine Zuweisungen eh weg.

p80286 16. Mär 2011 09:43

AW: For in For dann Goto
 
Die Schleifenvariable kann undefiniert sein.
Dann nimm ein Repeat Until oder ein While und Du hast eine Schleife und Deine Variable ist definiert.

Gruß
K-H

WM_CLOSE 16. Mär 2011 10:44

AW: For in For dann Goto
 
Und warum nicht so:
Delphi-Quellcode:
var
  boBreak:Boolean;
begin
  for a := 0 to 10 do
  begin
    for b := 0 to 20 do
    begin
      ...
      if ... then
      begin
        boBreak:=True;
        Break;
      end;
    end;
    if boBreak then
      break;
    if ... then Break;
  end;
end;
?

JamesTKirk 16. Mär 2011 13:17

AW: For in For dann Goto
 
Zitat:

Zitat von himitsu (Beitrag 1088907)
Warum sollte es reichen?

Diese Variableninhalte sind nach der Schleife undeffiniert.
Davor Zu Beginn wird es von Delphi automatisch initialisiert.
(nämlich mit dem Wert nach dem
Delphi-Quellcode:
:=
des For-To/Downto-Do)
Und wie grade erwähnt, optimiert der Compiler deine Zuweisungen eh weg.

Während ich voll zustimme, dass man normalerweise nicht nach der Schleife auf die Werte der Schleifenvariablen zugreifen sollte, so gibt es doch folgenden Eintrag in der Hilfe zu der zitierten Warnung: W1037: FOR-Loop variable '%s' may be undefined after loop (Delphi)

Besonders hervorheben möchte ich folgenden Absatz:
Zitat:

You can only rely on the final value of a for loop control variable if the loop is left with a goto or exit statement.
Wer hat nun Recht? Die Hilfe oder alle, die sagen, dass man nicht drauf zugreifen darf?

Gruß,
Sven

Medium 16. Mär 2011 13:50

AW: For in For dann Goto
 
Es ist hier doch überhaupt nicht das Problem, wenn die Schleife via Goto verlassen wird. Das Problem ist, dass der Code hinter dem Label auch ausgeführt wird, wenn die Bedingung vor dem Goto niemals zutrifft! Von daher ist diese Warnung mit diesem Wortlaut auch völlig korrekt - das hatte ich aber auf Seite eins schon gesagt. Das und NUR das ist das konkrete Problem, von all der Goto-Diskussion unberührt, die natürlich wieder auf 3 Seiten breit gezogen werden musste, weil man es ja so selten und unzureichend bespricht...

Satty67 16. Mär 2011 14:01

AW: For in For dann Goto
 
Statt dem GOTO könnte man eine Sub-Procedure aufrufen und hätte dann das Problem mit dem ereignislosen Scheifendurchlauf auch gleich gelöst:

Delphi-Quellcode:
procedure Something;

  procedure OnlyIfTrue;
  begin
    //
  end;

var
  a,b : IntegerM
begin
  for a := 0 to 10 do
    for b := 0 to 20 do
      if True then
      begin
        OnlyIfTrue;
        Exit;
      end;
end;

demic 16. Mär 2011 16:56

AW: For in For dann Goto
 
Hallo,

so viele Nachrichten... alles wegen Goto :)
Also "PRINT" und "GOTO" waren die ersten Befehle die ich gelernt hatte... zumindest auf dem C64 :)

Aber erst mal Danke für die vielen Vorschläge. Ich hatte den Code vereinfacht. Der richtige Code behandelt 3 StringGrids, sprich nach dem ersten Doppel-FOR das gleiche noch 2x, deshalb ist ein EXIT nicht auf einfacher Weise möglich. Zu der "If Prüfung Then Goto ForEnd"... es ist eine Prüfung die 100% eintritt aber das weis Delphi ja nicht, deshalb wohl die Warnung.

Ich bin heute auf folgende Idee gekommen. Hier der richtige Code:
Delphi-Quellcode:
Procedure TForm1.CheckGridCell(DG : TmyGrid);
Var NCol,NRow,i : LongInt;
Begin
 With DG Do
 Begin
  SelPaint := False;
  For NCol := 0 to ColCount-1 Do
  Begin
   For NRow := 0 to RowCount-1 Do
   Begin
    i := (NCol*(RowCount)) + NRow;
    If ACell = Dirlist[i].Name Then
    Begin
     Row := NRow;
     Col := NCol;
     If ShowStyle = ssFull Then
     begin
      if row < toprow then toprow := row
      else if row > toprow+visiblerowcount-1 then toprow := row-visiblerowcount+1;
     end;
     SelPaint := True;
     RePaint;
     Exit;
    End;
   End;
  End;
 End;
End;
Ich rufe an den nötigen Stellen die Prozedur 3x auf.
Delphi-Quellcode:
CheckGridCell(Grid1);
CheckGridCell(Grid2);
CheckGridCell(Grid3);
Mit der Parameterübergabe hat der Inhalt der Prozedur auch weniger Zeilen und ein EXIT kann ich so einsetzen. Warnungen gibt's von Delphi so auch nicht mehr.

Auch Danke für den Tipp, zum einfügen von Delphi-Code.

Gruß
Michael


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:52 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz