Claus Schönleber

Hitchhacker´s Guide To PASCAL  [Vol. 1]

 [ zurück | weiter ]
   [ Start | Beispielprogramme Download | Home ]

Inhalt

Compiler
Programmieren
Datentypen,
Variablen,
Standardfunktionen
Logik
Verzweigung,
Strukturierung
Schleifen
Felder (Arrays)
Verteiler: CASE
Zeichenketten
(Strings)
Textdateien
Module
(Prozeduren,
Funktionen)
Anhang
(Operatoren,
abgeleitete
Funktionen)
 
 
 

 

 

Schleifen 

Außer Verzweigungen braucht man häufig Konstruktionen, die viele Wiederholungen der gleichen oder einer ähnlichen Anweisungsliste ermöglichen. Das erledigen Schleifen. 
Schleife
Eine Schleife ist eine Struktur, die es erlaubt, einen PASCAL-Block beliebig oft hintereinander auszuführen. Die Anzahl der Schleifendurchläufe wird durch eine Abbruchbedingung gesteuert. 
Beispiele
(siehe folgende Programmbeispiele) 
Abbruchbedingung
Eine Abbruchbedingung ist ein logischer Ausdruck, der vor oder nach jedem Schleifendurchlauf überprüft wird. Ändert sich der
Zustand der Auswertung des Ausdrucks, wird die Schleife beendet und mit der Anweisung fortgefahren, die auf den die Schleife
enthaltenden PASCAL-Block folgt. 
Beispiele
(siehe folgende Programmbeispiele) 
In PASCAL gibt es drei verschiedene Möglichkeiten. 

Zählschleifen 

Die erste Schleife, die Sie kennenlernen sollen, ist die Zählschleife, die auch manchmal "FOR-Schleife" genannte wird. 

Eine "FOR-Schleife" sieht folgendermaßen aus: 

   FOR <variable> := <ausdruck> TO <ausdruck> DO 
     <block> 
Dabei wird die <variable> Laufvariable genannt, welcher der erste <ausdruck> als Startwert zugewiesen wird. Im zweiten <ausdruck> wird der Endwert dargestellt. Meist bestehen beide Ausdrücke nur aus Konstanten oder einzelnen Variablen. Der Typ von <variable> kann integer, boolean, char oder jeder selbst definierte Typ sein (siehe später). Die Schrittweite ist vordefiniert (+1) und in dieser Art der Schleife nicht änderbar! Der Startwert muß natürlich kleiner sein als der Endwert. Die Alternative ist einzig eine umgekehrte Zählweise. Wenn die Schleife abwärts zählen soll, tauscht man einfach das TO gegen ein DOWNTO aus. Damit wählt man die Schrittweite -1. In diesem Fall muß der Startwert größer sein als der Endwert. 

Ein erstes kleines Beispiel für eine Zählschleife: 

  PROGRAM for_schleife; 
    VAR index,finish : integer; 
  BEGIN 
    finish := 10; 
    writeln ('Zählschleifenbeispiel'); 
    FOR index := 1 TO finish DO 
      writeln ('Inhalt von index: ',index); 
    writeln ('Ende der Schleife'); 
    writeln ('index nach der Schleife: ',index); 
  END. 
Die Funktionsweise dieser Schleife ist wie folgt: 
  1. Bei Beginn der FOR-Schleife wird der Laufvariablen "index" der Startwert 1 zugewiesen. 
  2. Danach wird der aktuelle Inhalt von index mit dem Endwert verglichen. 
  3. Ist der Inhalt von index größer als der Endwert (finish), dann wird die Schleife beendet und mit der der Schleife folgenden Anweisung fortgefahren. 
  4. Ist der Inhalt von index kleiner oder gleich dem Endwert, wird zum Inhalt der Laufvariablen die Schrittweite addiert und der die Schleife enthaltende Block wieder ausgeführt. 
Merksatz: Die Laufvariable darf während eines Durchlaufs nicht durch Eingriff von außen verändert werden! 

Es ist nicht nur schlechter Programmierstil, es ist auch abhängig vom Compiler, ob und auf welche Weise das funtkioniert. 

Das bedeutet, daß Sie innerhalb einer Schleife der Laufvariablen keinen Wert zuweisen dürfen. Wenn Sie innerhalb einer Schleife den Wert der Laufvariablen unbedingt ändern müssen, benutzen Sie am besten eine der anderen Schleifenkonstruktionen und bauen dort selbst eine Zählvariable ein. 

Auch "FOR-Schleifen" kann man schachteln. Vielleicht ist an dieser Stelle noch nicht einsehbar, warum man das machen müßte, aber man sollte sich wenigstens mit der Funktionsweise vertraut machen. 

  PROGRAM doppel_schleife; 
    VAR a,b,finish : integer; 
  BEGIN 
    finish := 10; 
    writeln ('Zählschleifenbeispiel'); 
    FOR a := 1 TO finish DO 
    BEGIN 
      writeln ('Die innere Schleife beginnt erneut...'); 
      FOR b := 1 TO finish DO 
        writeln ('a = ',a,' b = ',b); 
    END; 
    writeln ('Ende der Schleife'); 
  END. 
Wie funktioniert das? Ganz einfach! Der Inhalt der äußeren Schleife ist, abgesehen von der Textausgabe, die 10 mal ausgeführt wird, die
innere Schleife. Somit wird die innere Schleife 10 mal vollständig abgearbeitet. Die innere Schleife einmal vollständig abzuarbeiten bedeutet, die "writeln"-Prozedur 10 mal auszuführen. Ergo dessen wird die "writeln"-Prozedur 10 mal 10 gleich 100 mal ausgeführt.

Die Voraussetzung für solche Zählschleifen ist die Kenntnis der Anzahl der Durchläufe. Nur wenn auf irgendeine Weise vor dem Beginn der Schleife berechenbar ist, wie oft der Schleifenblock durchzuführen ist, kann sie eingesetzt werden. Das ist aber nicht immer möglich. Dann kommen die beiden anderen Schleifenarten zum Einsatz. 

Die WHILE-Schleife 

Diese Schleife benötigt ebenfalls einen logischen Ausdruck, der aber jetzt explizit hingeschrieben werden muß. Bei der Zählschleife war das nicht notwendig, da die Schleife den Vergleich zwischen Inhalt der Laufvariablen und Endwert selbständig vornimmt. 

Hier kann man jede beliebige Bedingung verwenden. Das sieht dann so aus: 

  WHILE <logischer ausdruck> DO 
    <block> 
Die Funktionsweise ist wiederum höchst einfach. Solange die Auswertung von <logischer ausdruck> das Ergebnis true liefert, wird der <block> wiederholt ausgeführt. Kommt als Ergbenis false heraus, wird mit der dem Schleifenblock folgenden Anweisung weitergemacht. 

Wichtig an dieser Schleifenart ist die Tatsache, daß die Abbruchbedingung vor dem Eintritt in die Schleife geprüft wird. Das bedeutet, daß die Schleife gar nicht erst ausgeführt wird, wenn die Abbruchbedingung schon von Anfang an false liefert. Man braucht das in vielen Fällen, um Fehlfunktionen zu verhindern. Solche Schleifen heißen abweisend.

Ein Beispiel. Das Programm soll zunächst nichts anderes machen als das vorige "FOR"- Beispiel (allerdings nur dreimal, stat zehnmal): 

PROGRAM while_schleife; 
  VAR a,finish : integer; 
BEGIN 
  finish := 3; 
  writeln ('Die 1. WHILE-Schleife'); 
  a := 1; 
  WHILE (a <= finish) DO 
  BEGIN 
    writeln ('a = ',a:2,' Abbruchbed.: ',a <= finish); 
    a := succ (a); 
  END; 
  writeln ('Werte nach dem Ende der Schleife:'); 
  writeln ('a = ',a:2,' Abbruchbed.: ',a <= finish); 
END. 
Da wir die WHILE-Schleife hier als Zählschleife "mißbrauchen", müssen wir eine Laufvariable selbst definieren und auch selbst verwalten. Das bedeutet, sie muß initialisiert werden (mit einem Anfangswert versehen werden), sie muß explizit durch eine Anweisung hochgezählt werden (a := succ (a)) und es muß die Abbruchbedingung explizit aufgeführt werden. Hier ist es jedoch möglich die Schrittweite beliebig zu wählen. Indem wir den Typ der Variablen "a" auf real ändern, ist es sogar möglich, in gebrochenen Schritten zu arbeiten. 

Um Ihnen zu zeigen, wie die Auswertung der Abbruchbedingung abläuft, wird das Ergebnis des logischen Ausdrucks jedesmal in der Schleife und einmal nach dem Schleifenende angezeigt. Was dann ausgegeben wird? Ganz einfach! Es werden die Werte true oder false ausgegeben, je nach Ergebnis. Die Bildschirmausgabe sieht dann so aus: 
 

Die 1. WHILE-Schleife 
a = 1 Abbruchbed.: true 
a = 2 Abbruchbed.: true 
a = 3 Abbruchbed.: true 
Werte nach dem Ende der Schleife: 
a = 4 Abbruchbed.: false 
[Bildschirmausgabe WHILE-Beispiel]

Nun ist der Sinn der WHILE-Schleife ja nicht gerade im Zählen zu suchen; dafür gibt es die FOR-Schleife. Wir wollen also ein zwar
einfaches, aber zweckmäßiges Beispiel untersuchen. Das Programm erwartet die Eingabe von Zeichen im Bereich 'A' bis 'Z'. 

  PROGRAM while_schleife2; 
    VAR zahl      : integer; 
        zeichen   : char; 
        buchstabe : boolean; 
  BEGIN 
    zahl := 1; 
    writeln ('Beliebigen Buchstaben (A..Z) eingeben: '); 
    readln (zeichen); 
    buchstabe := (zeichen >= 'A') AND (zeichen =< 'Z'); 
    IF NOT buchstabe THEN 
      writeln ('Das war kein großer Buchstabe!') 
    ELSE 
    BEGIN 
      WHILE (chr (zahl + 64) < zeichen) DO 
        zahl := succ (zahl); 
      writeln ('Der Buchstabe war: ',zeichen); 
      writeln ('Nummer ',zahl,' im Alphabet.'); 
    END; 
  END. 
Was das Programm macht? Es zählt auf sehr umständliche Weise, an wievielter Stelle ein Großbuchstabe im Alphabet steht. Da nicht bekannt ist, welcher Buchstabeeingegeben wird, kann man keine FOR-Schleife verwenden (es sind natürlich auch andere Lösungen möglich). Sobald der Buchstabe erreicht ist, kann mit dem Zählen aufgehört werden. Eine kleine Bemerkung zu den beiden logischen ausdrücken: 

Die Variable buchstabe: 

Hier wird geprüft, ob das eingegebene Zeichen im erlaubten Bereich ('A'..'Z') liegt. Wenn nicht, erfolgt eine Fehlermeldung. Andernfalls erfolgt die Bearbeitung. Solche Fehlerbehandlungen sind notwendig und müssen in jedem Programm dafür sorgen, daß der Anwender nicht mit einem unbeabsichtigten und fehlerhaften Programmende konfrontiert wird. Wir werden noch andere kennenlernen. 

Die Funktion chr (zahl + 64): 

Um von der bisher berechneten Nummer auf den Code des dazugehörenden Buchstabens zu schließen, muß die Konstante 64 addiert werden, da die Codes der Großbuchstaben im Bereich 65 bis 90 liegen. Dadurch können wir auf den bisher erreichten Buchstaben schließen und ihn mit dem eingegebenen vergleichen. 

Die REPEAT..UNTIL-Schleife 

Diese Form der Schleife hat sehr viel mit der WHILE-Schleife gemeinsam. Es gibt jedoch zwei gravierende Unterschiede, und der ist es, der die REPEAT-Schleife rechtfertigt. Um die Unterschiede zwischen beiden Schleifenarten klar zu machen, seien sie hier in einer Tabelle gegenübergestelllt: 
 
WHILE REPEAT..UNTIL 
Abbruchbedingung wird vor Schleifenrumpf geprüft.

Die Schleife läuft, solange die Auswertung der Abbruchbedingung true ergibt. 
 

Abbruchbedingung wird nach Schleifenrumpf geprüft.

Die Schleife läuft, solange die Auswertung der Abbruchbedingung false 
ergibt. 
 

[Eigenschaften WHILE/REPEAT]

Man sieht es deutlich in der Tabelle: Die REPEAT- Schleife arbeitet, bis die Abbruchbedingung wahr ist, die WHILE-Schleife arbeitet,
solange die Abbruchbedingung wahr ergibt. Diese Schleifenkonstruktion ist nicht abweisend.

Im übrigen gibt es hier noch eine Besonderheit: 

Der Schleifenblock muß nicht in BEGIN und END eingeschlossen werden, da die beiden PASCAL-Worte REPEAT und UNTIL den Block schon eindeutig klammern! Hier können wir also auf die übliche Blockklammerung verzichten, was die Übersichtlichkeit, so finde ich jedenfalls, wieder erhöht, da diese Form der Schleife sofort im Quelltext erkannt werden kann. 

Nun also auch ein Beispiel für eine REPEAT..UNTIL- Schleife. Solche Schleifen haben den Vorteil, daß Variablen in der Abbruchbedingung nicht initialisiert werden müssen, weil sie ihren Wert oft erst in der Schleife bekommen! Deswegen wird diese Schleife gerne bei Eingabroutinen verwendet, um fehlerhafte Eingaben zu vermeiden und die Eingabeaufforderung wiederholen zu können. 

  PROGRAM repeat_beispiel; 
    VAR c         : char; 
        buchstabe : boolean; 
  BEGIN 
    writeln ('Simples REPEAT-Beispiel:'); 
    REPEAT 
      write ('Buchstaben eingeben: '); 
      readln (c); 
      buchstabe := ((c >= 'A') AND (c =< 'Z')) OR ((c >= 'a') AND (c =< 'z')) 
    UNTIL buchstabe; 
    writeln ('Herzlichen Glückwunsch!'); 
  END. 
Zugegeben, das Programm tut nicht sehr viel. Aber wie immer in solch einem Fall wollen wir ja nur die Funktionsweise der besprochenen
Struktur erkennen. Mit der Variablen "buchstabe" prüfen wir die Einhaltung des Bereichs, diesmal große und kleine Buchstaben. Versuchen Sie als Übung nachzuvollziehen, wie der logische Ausdruck arbeitet. 

Mit REPEAT..UNTIL werden oft ganze Programme oder große Teile eingeschlossen, um eine Wiederholung zu ermöglichen, wie wir noch sehen werden.

 

 [ zurück | weiter ]
   (c) 2001 Schoenleber.com