Schleife

Vier Schleifentypen: for / while / repeat / for-in

Sehen Sie sich zuerst die folgenden Beispiele an. Ändern Sie die Codedatei aus der vorherigen Lektion, mydemo.dpr, und ändern Sie die Dateiendung zu pas, also mydemo.pas. Das ist die Standard-Endung für Pascal-Quelldateien. Laden Sie anschließend einen Code-Editor wie Notepad++ mit Syntaxhervorhebung herunter – dadurch wird der Code deutlich übersichtlicher.

Unten finden Sie ein vollständiges Beispiel mit Zeilenkommentaren. Nach dem Codebeispiel erklären wir jede Anweisung Schritt für Schritt.

// 2.8 Schleifenanweisungen: for, while, repeat, for..in
{$ifdef FPC} {$mode objfpc}{$H+}{$J-} {$endif}
// FPC-Compilerdirektiven: Objektmodus aktivieren, lange Strings, automatische String-Referenzzählung deaktivieren
{$ifdef MSWINDOWS} {$apptype CONSOLE} {$endif}
// Windows-Plattform: Programm als Konsolenanwendung markieren (kein GUI-Fenster)
{$R+} // Bereichsprüfung aktivieren, sehr hilfreich zum Debuggen von Array-Indexfehlern
var
  MyArray: array [0..9] of Integer; // Ganzzahlarray mit 10 Elementen, Indizes 0 bis 9
  I: Integer; // Schleifenzähler-Variable
begin
// 1. Aufsteigende for-Schleife: Array initialisieren, Quadrate von 0 bis 9 speichern
for I := 0 to 9 do
    MyArray[I] := I * I;

// 2. Einfache for-Schleife zum Durchlaufen der Array-Indizes und Ausgeben der Quadrate
for I := 0 to 9 do
    WriteLn('Quadratwert: ', MyArray[I]);

// 3. Low/High holen automatisch die Array-Grenzen, keine fest eingetragenen 0 und 9, besser erweiterbar
for I := Low(MyArray) to High(MyArray) do
    WriteLn('Quadratwert: ', MyArray[I]);

// 4. while-Schleife: Zuerst Bedingung prüfen, nur bei wahrer Bedingung Schleifenkörper ausführen
  I := 0;
while I < 10 do
begin
    WriteLn('Quadratwert: ', MyArray[I]);
    I := I + 1; // Äquivalente Schreibweisen: I+=1 / Inc(I)
end;

// 5. repeat-until-Schleife: Schleifenkörper einmal ausführen, am Ende die Abbruchbedingung prüfen
  I := 0;
repeat
    WriteLn('Quadratwert: ', MyArray[I]);
    Inc(I); // Zähler erhöhen
until I = 10;

// 6. for-in-Durchlauf: Direkt Elementwerte auslesen, ohne Indexmanipulation
for I in MyArray do
    WriteLn('Quadratwert: ', I);
end.Code-Sprache: PHP (php)

Unten steht der Code ohne alle Kommentare

{$ifdef FPC} {$mode objfpc}{$H+}{$J-} {$endif}
{$ifdef MSWINDOWS} {$apptype CONSOLE} {$endif}
{$R+}

var
  MyArray: array [0..9] of Integer;
  I: Integer;

begin

for I := 0 to 9 do
    MyArray[I] := I * I;

for I := 0 to 9 do
    WriteLn('Quadratwert: ', MyArray[I]);

for I := Low(MyArray) to High(MyArray) do
    WriteLn('Quadratwert: ', MyArray[I]);

  I := 0;
while I < 10 do
begin
    WriteLn('Quadratwert: ', MyArray[I]);
    I := I + 1;
end;

  I := 0;
repeat
    WriteLn('Quadratwert: ', MyArray[I]);
    Inc(I);
until I = 10;

for I in MyArray do
    WriteLn('Quadratwert: ', I);

end.Code-Sprache: PHP (php)

Im Folgenden analysieren wir den Code jeder Schleife Schritt für Schritt

for-Schleife

Werte einem Array mit einer for-Schleife zuweisen

{$ifdef FPC} {$mode objfpc}{$H+}{$J-} {$endif}
{$ifdef MSWINDOWS} {$apptype CONSOLE} {$endif}
{$R+}

var
  MyArray: array [0..9] of Integer;
  I: Integer;

begin

for I := 0 to 9 do
    MyArray[I] := I * I;

end.Code-Sprache: PHP (php)

Dieser Code gliedert sich in drei Bereiche: Oben stehen Präkompilieranweisungen, im var-Bereich werden Variablen deklariert (ein Array, eine Ganzzahl), der Hauptausführungsblock zwischen begin und end. enthält eine for-Schleife, die nacheinander Werte von 0 bis 9 an I übergibt und per Index das Array befüllt.

Wir belegen die zehn Array-Elemente MyArray[0] bis MyArray[9]. Das Sternchen * ist der Multiplikationsoperator.

MyArray[0] := 0 * 0;

MyArray[1] := 1 * 1;

MyArray[9] := 9 * 9;

Fügen Sie unter der ersten for-Schleife eine weitere for-Schleife hinzu, um alle im Array gespeicherten Elemente auszulesen.

Nach Kompilieren und Ausführen werden alle gespeicherten Werte ausgegeben

Alle Ausgaben sind die Quadrate von 0 bis 9 und stimmen mit unseren vorherigen Erwartungen überein.

Wenn Sie den Indexbereich eines Arrays nicht kennen, nutzen Sie eingebaute Funktionen, um die untere und obere Grenze abzufragen.

Die obige Funktion Low(Arrayname) liefert den kleinsten Indexwert eines Arrays

  • Low(Typ/Variable): Ermittelt den Minimalwert / untere Grenze von Ordinaltypen, Arrays, Mengen
  • High(Typ/Variable): Ermittelt den Maximalwert / obere Grenze von Ordinaltypen, Arrays, Mengen

while- und repeat-Schleifen

Innerhalb des mit begin end; umschlossenen while-Schleifenkörpers wird die Variable I am Ende des Blocks um 1 erhöht. Nach der Erhöhung springt der Programmablauf zurück zu while I < 10 do für eine neue Bedingungsprüfung. Ist die Bedingung wahr, läuft der Schleifenkörper erneut, I steigt wieder um 1, die Prüfung wiederholt sich. Der Vorgang endet erst, wenn I < 10 unwahr wird – also sobald I den Wert 10 erreicht.

Wesentliche Unterschiede zwischen while und repeat-until

  1. Entgegengesetzte Prüflogik
  • while Bedingung do: Bedingung wahr → Schleife fortsetzen; Bedingung unwahr → Schleife verlassen
  • repeat ... until Bedingung: Bedingung wahr → Schleife verlassen; Bedingung unwahr → Schleife fortsetzen
  1. Garantierte Mindestausführungen unterschiedlich
  • while: Ist die Anfangsbedingung unwahr, wird der Schleifenkörper gar nicht ausgeführt
  • repeat-until: Unabhängig von der Bedingung läuft der Schleifenkörper mindestens einmal

Wenn Sie Sprachen wie C, C++ oder Java gelernt haben, verstehen Sie es sofort: repeat-until funktioniert genau wie do-while. Zuerst läuft der Schleifeninhalt einmal, dann wird die Bedingung nach until geprüft. Ist sie unwahr, wiederholt sich die Schleife.

Bei repeat-until brauchen Sie kein begin und end, repeat bis until bildet von Haus aus einen einzigen Codeblock. Sie können begin end optional ergänzen, es ist aber nicht empfehlenswert.

Der wörtliche Sinn von repeat-until lautet „Wiederhole … bis“, die Funktionsweise ist am Begriff selbst leicht abzulesen.


Beim Durchlaufen werden nacheinander alle Werte aus MyArray an I zugewiesen, sodass Sie I direkt im Schleifenkörper bearbeiten können. Es ist nicht nötig, den Index manuell zu erhöhen – Sie brauchen sogar gar keinen Index, bis das gesamte Array durchlaufen ist.

Erläuterung der klassischen for-Schleife (for I := ... to/downto)

  1. Ähnlich der C-for-Schleife, aber restriktiver: Nur zusammenhängende Ordinalwerte (Ganzzahlen, Enums) können durchlaufen werden;
  2. Rückwärtsdurchlauf mit downto unterstützt: for I := 9 downto 0 do;
  3. Die Grenzen Low(xx) / High(xx) werden nur einmal beim Start der Schleife berechnet – hohe Laufzeiteffizienz;
  4. Nach regulärem Schleifenende ist der Wert von I undefiniert, der Compiler gibt eine Warnung aus. Bei vorzeitigem Abbruch mit Break oder Exit behält I seinen aktuellen Wert.

for-in-Durchlauf (moderner foreach-Stil)

Kann vier Datentypen durchlaufen, ohne manuell Indizes zu verwalten:

  1. Arrays: Direkt jeden Elementwert auslesen (in vorherigen Beispielen demonstriert)
  2. Enumerationstypen
{$ifdef FPC} {$mode objfpc}{$H+}{$J-} {$endif}
{$ifdef MSWINDOWS} {$apptype CONSOLE} {$endif}
{$R+}

type TAnimalKind = (Duck,Cat,Dog);

var AK:TAnimalKind;
begin
  for AK in TAnimalKind do 
    WriteLn(AK);
end.Code-Sprache: PHP (php)
  1. Mengentypen
{$ifdef FPC} {$mode objfpc}{$H+}{$J-} {$endif}
{$ifdef MSWINDOWS} {$apptype CONSOLE} {$endif}

type
  // Enumerationstyp definieren
  TAnimalKind = (Duck, Cat, Dog);
  // Auf Enum basierenden Mengentyp erstellen
  TAnimals = set of TAnimalKind;

var
  Animals: TAnimals;
  AK: TAnimalKind;
begin
  // Zwei Enum-Werte in die Menge schreiben: Duck und Cat
  Animals := [Duck, Cat];

  // Mit for-in alle vorhandenen Mitglieder der Menge durchlaufen
  for AK in Animals do
  begin
    WriteLn('Gefundenes Tier: ', AK);
  end;
end.Code-Sprache: PHP (php)
  1. Generische Listen (lernen wir in späteren Kapiteln)
{$ifdef FPC} {$mode objfpc}{$H+}{$J-} {$endif}
{$ifdef MSWINDOWS} {$apptype CONSOLE} {$endif}
uses
  SysUtils, Generics.Collections; // Unit für generische Container einbinden

type
  TMyClass = class  // Eigene Klasse zum Speichern von Zahl und Quadrat
    I, Square: Integer;
  end;
  // Generische Objektliste instanziieren, automatische Lebenszyklusverwaltung
  TMyClassList = {$ifdef FPC}specialize{$endif} TObjectList&lt;TMyClass&gt;;
var
  List: TMyClassList;
  C: TMyClass;
  I: Integer;
begin
  List := TMyClassList.Create(true); // true: interne Objekte beim Zerstören der Liste automatisch freigeben
try
  // Objekte in Schleife erstellen und der Liste hinzufügen
for I := 0 to 9 do
begin
      C := TMyClass.Create;
      C.I := I;
      C.Square := I * I;
      List.Add(C);
end;
  // Mit for-in jedes benutzerdefinierte Objekt in der Liste direkt durchlaufen
for C in List do
      WriteLn('Das Quadrat von ', C.I, ' ist ', C.Square);
finally
    FreeAndNil(List); // Liste sicher freigeben, Speicherlecks vermeiden
end;
end.
Code-Sprache: HTML, XML (xml)

Hinweis: Dieses Beispiel nutzt Klassen und Generika. Anfänger können es vorerst überspringen, wir erklären es detailliert im Kapitel zur objektorientierten Programmierung.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert