Programmierkurs: Delphi: Pascal: Schleifen

Aus Wikibooks
Zur Navigation springen Zur Suche springen

Schleifen[Bearbeiten]

Die while-Schleife (Kopfgesteuerte-Schleife)[Bearbeiten]

Die while-Schleife ermöglicht es, einen Programmcode so oft auszuführen, solange eine Bedingung erfüllt ist. Ist die Bedingung schon vor dem ersten Durchlauf nicht erfüllt, wird die Schleife übersprungen.

while <Bedingung> do
  <Programmcode>

Hierbei wird vor jedem Durchlauf die Bedingung erneut überprüft.

Beispiel:

var
  a, b: Integer;
begin
  a := 100;
  b := 100;
  while a >= b do
  begin
    Writeln('Bitte geben Sie einen Wert < ', b, ' ein.');
    Readln(a);
  end;
end.

Die Schleife wird mindestens einmal durchlaufen, da zu Beginn die Bedingung 100 = 100 erfüllt ist.

Die repeat-until-Schleife (Fußgesteuerte-Schleife)[Bearbeiten]

Die repeat-until-Schleife ähnelt der while-Schleife. Hier wird die Bedingung jedoch nach jedem Durchlauf überprüft, so dass sie mindestens einmal durchlaufen wird.

repeat
  <Programmcode>
until <Bedingung>;

Des Weiteren wird die repeat-until-Schleife im Gegensatz zur while-Schleife so lange durchlaufen, bis die Bedingung erfüllt ist.

Das obere Beispiel:

var
  a, b: Integer;
begin
  b := 100;
  repeat
    Writeln('Bitte geben Sie einen Wert < ', b, ' ein.');
    Readln(a);
  until a < b;
end.

Hier ist dieser Schleifentyp von Vorteil, da die Initialisierung von a entfällt, weil die Schleife mindestens einmal durchlaufen wird.

Ein weiterer Vorteil der repeat-until-Schleife ist, dass sie die einzige Schleife ist, die ohne Schachtelung auskommt, da der Programmcode von repeat und until bereits eingegrenzt ist. Bei den anderen Schleifen folgt der Programmcode immer der Schleifendeklaration.

Die for-to-/for-downto-Schleife[Bearbeiten]

Im Gegensatz zu den anderen beiden Schleifentypen basiert die for-Schleife nicht auf einer Bedingung, sondern auf einer bestimmten Anzahl an Wiederholungen.

 for variable := <untergrenze> to <obergrenze> do
   <Programmcode>
 for variable := <obergrenze> downto <untergrenze> do
   <Programmcode>

Der Unterschied zwischen den beiden Schleifen liegt darin, dass die erste von unten nach oben, die zweite jedoch von oben nach unten zählt. Falls die Untergrenze größer als die Obergrenze ist, wird jedoch nichts ausgeführt.

Beispiele:

for i := 0 to 4 do
  Writeln(i);
Ausgabe:
0
1
2
3
4
for i := 4 downto 0 do
  Writeln(i);
Ausgabe:
4
3
2
1
0
for i := 4 to 3 do
  Writeln(i);
Ausgabe:
-keine-
for i := 4 to 4 do
  Writeln(i);
Ausgabe:
4

Es ist auch möglich, als Ober- und/oder Untergrenze Variablen anzugeben:

for i := a to b do
  Writeln(i);

Die Schleife verhält sich hierbei genauso wie die Variante mit Konstanten.

Als Variablentyp ist nicht nur Integer erlaubt: for-Schleifen unterstützen alle Ordinalen Typen, also Integer, Aufzählungen und Buchstaben.

Beispiele:

var
  i: Integer;
begin
  for i := 0 to 10 do
    Writeln(i);
end.
var
  c: Char;
begin
  for c := 'a' to 'z' do
    Writeln(c);
end.
type
  TAmpel = (aRot, aGelb, aGruen);
var
  ampel: TAmpel;
begin
  for ampel := aRot to aGruen do
    Writeln(Ord(ampel));
end.

Im Gegensatz zu while- und repeat-until-Schleifen darf in einer for-Schleife die Bedingungsvariable nicht geändert werden. Daher führt folgender Abschnitt zu einer Fehlermeldung:

for i := 0 to 5 do
begin
  i := i - 1;  // <-- Fehler
  Writeln(i);
end;


Die for-in-Schleife[Bearbeiten]

Bei dieser, erst in neueren Delphi-Versionen vorhandenen Schleifenart, handelt es sich um eine aus Listen auswählende Schleife. Diese geht alle Elemente einer Liste durch und übergibt an die Laufvariable jeweils den aktuellen Listeneintrag. Die Anzahl der Durchläufe bestimmt sich durch die Länge der Liste. Die for-in-Schleife ist folgendermaßen aufgebaut:

for variable in liste do
  <Anweisung>;

Der Begriff „Liste“ ist hierbei recht weit gefasst. Als Listenvariable kann sowohl ein Array, wie auch ein Set oder ein String verwendet werden. Auch einige Klassen (z.B. TList, TStrings oder TToolBar) unterstützen diese Auswertung.

Der Typ der Laufvariablen muss immer einem einzelnen Element der Liste entsprechen. Bei String wäre dies Char, bei einem array of Byte der Typ Byte.

Der Vorteil der for-in-Schleife liegt darin, dass man eine Zählvariable spart und an Ort und Stelle den Werte eines Listenelements geliefert bekommt. Vor allem muss man hierbei die Grenzen der Liste nicht kennen oder auswerten, also mit welchem Index sie beginnt und endet.

Die folgenden beiden Beispiele sind gleichbedeutend:

{ ab Delphi 2005 }
var
  Lottozahlen: array[1..6] of Byte = (2, 3, 5, 7, 11, 13);
  Element: Byte;

begin
  for Element in Lottozahlen do
    Writeln(Element);
end.
{ vor Delphi 2005 }
var
  Lottozahlen: array[1..6] of Byte = (2, 3, 5, 7, 11, 13);
  Zaehler: Byte;

begin
  for Zaehler := 1 to 6 do
    Writeln(Lottozahlen[Zaehler]);
end.

Hinweis für Benutzer von FreePascal: FreePascal unterstützt for-in-Schleifen erst ab Version 2.4.2.

Vorzeitiger Abbruch einer Schleife[Bearbeiten]

In manchen Fällen ist es hilfreich, dass nicht jeder Schleifendurchgang komplett ausgeführt wird, oder dass die Schleife bereits früher als von der Schleifenbedingung vorgegeben verlassen werden soll. Hierfür stehen die Routinen Continue und Break zur Verfügung.

Beispiel: Sie suchen in einer Liste von Strings eine bestimmte Zeichenfolge:

var
  a: array[1..5] of string;
  i: Integer;
  e: Boolean;

begin
  a[1] := 'Ich';
  a[2] := 'werde';
  a[3] := 'dich';
  a[4] := 'schon';
  a[5] := 'finden!';

  e := False;
  i := 1;

  repeat
    if a[i] = 'dich' then
      e := True
    else
      Inc(i);
  until e or (i > 5);

  if i <= 5 then
    Writeln('Das Wort "dich" wurde an Position ', i, ' gefunden.')
  else
    Writeln('Das Wort "dich" wurde nicht gefunden.');
end.

In diesem Beispiel steht das gesuchte Wort „dich“ an der Position 3 in der Liste. Um nicht alle Elemente durchzusuchen, haben wir hier eine repeat-until-Schleife verwendet, die dann beendet wird, sobald das Wort gefunden wird. Jedesmal, wenn das Wort nicht gefunden wurde, wird der Index um 1 erhöht.

Einfacher wäre eine for-Schleife. Diese durchsucht alle Elemente und gibt nach einem definierten Abbruch den letzten Zählwert zurück. Um den rechtzeitigen Abbruch zu erreichen, verwenden wir die Anweisung Break:

  for i := 1 to 5 do
  begin
    if a[i] = 'dich' then
      Break;
  end;

Hier benötigen wir weder eine Prüfvariable, noch muss i vorher initialisiert werden. Auch hier erfolgt der Schleifenabbruch, sobald das Wort "dich" gefunden wurde. Dieser Abbruch kann jedoch in einer Zählschleife nicht sauber durch eine Bedingung erfolgen, sondern muss durch die Anweisung Break erzwungen werden. In diesem Falle erfolgen die Schleifendurchläufe mit den Werten 4 und 5 gar nicht.

Übrigens: Wird das Wort nicht gefunden und die Schleife somit vollständig durchlaufen, funktioniert unser Programm unter Delphi dennoch korrekt. Das liegt daran, dass die Zählvariable i praktisch immer am Ende des Schleifendurchlaufs erhöht wird und dann beim nächsten Sprung an den Anfang geprüft wird, ob die Obergrenze überschritten wurde. Läuft die Schleife also vollständig durch, hat die Zählvariable anschließend den Wert von Obergrenze + 1, in unserem Beispiel also 6. Bei der for-downto-Schleife gilt analog, dass die Zählvariable am Ende den Wert Untergrenze - 1 besitzt. FreePascal verhält sich hier anders. Da hat die Zählvariable am Ende der Schleife den jeweiligen Wert der Ober- bzw. Untergrenze (5 in unserem Falle). Hier müssten wir die 6 also selbst mit einbeziehen, um noch feststellen zu können, ob sich das Wort tatsächlich an der letzten Stelle befindet oder einfach nur die Schleife erfolglos durchgelaufen ist:

  for i := 1 to 6 do
  begin
    if i = 6 then
      Break;
    if a[i] = 'dich' then
      Break;
  end;

Die erste Prüfung auf i = 6 ist hierbei zwingend erforderlich. Würden wir bei der Zahl 6 keinen Abbruch vornehmen, käme als nächste Prüfung a[6] = 'dich'. Da das Array nur 5 Elemente besitzt, würde die zweite Prüfung zu einem Programmabsturz führen!


Man sollte nach Möglichkeit darauf verzichten, eine Schleife vorzeitig abzubrechen. Der Programmcode kann damit viel unübersichtlicher werden als nötig. In unserem Beispiel ist die Repeat-Until-Schleife vorzuziehen.

Überspringen von Werten[Bearbeiten]

Ein Schleifendurchlauf kann mit dem Befehl Continue an der entsprechenden Stelle unterbrochen und wieder am Anfang begonnen werden.

Beispiel: Ausgabe aller geraden Zahlen zwischen 1 und 10:

var
  i: Integer;

begin
  for i := 1 to 10 do
    if i mod 2 = 0 then
      Writeln(i);
end.

oder:

var
  i: Integer;

begin
  for i := 1 to 10 do
  begin
    if i mod 2 <> 0 then
      Continue;
    Writeln(i);
  end;
end.

Im oberen Beispiel werden die Werte vor der Ausgabe „gefiltert“. Das zweite Beispiel startet hingegen einen neuen Durchlauf, wenn eine Zahl nicht ohne Rest durch 2 teilbar ist. Der Vorteil der zweiten Variante liegt darin, dass mit einer geringeren Verschachtelungsebene gearbeitet werden kann. Die Ausgabe von i erfolgt noch immer im Programmcode der for-Schleife, während sie beim ersten Beispiel im Programmcode der if-Anweisung erfolgt.


Arrow left.png Pascal: Schachtelungen Inhaltsverzeichnis Pascal: Prozeduren und Funktionen Arrow right.png