Im ersten Teil dieses Kurses wurden schon einige wichtige Eigenschaften von Pascal besprochen. So zum Beispiel der Programmaufbau und der Vereinbarungs- und Anweisungsteil. AuĂerdem wurden schon folgende grundlegende Elemente behandelt:
Label
Konstanten
Variablen
- Zuweisung
read, readln
write, writeln
- formatierte Ausgabe
sqr(x), sqrt(x)
begin ... end
if ... then ...
if ... then ... else ...
Zum Erstellen von Programmen wurde das Struktogramm (auch Nassi-Shneiderman-Diagramm) eingefĂŒhrt. Es erleichtert das 'saubereâ bzw. strukturierte Programmieren und soll im weiteren Kurs ausgebaut werden. Ein weiteres Hilfsmittel fĂŒr die Programmierung in Pascal sind die Syntax-Diagramme. Sie zeigen eindeutig die Syntax aller Elemente und Strukturen der Sprache an. FĂŒr die ersten Programme sind sie nicht notwendig. Sie werden aber in einem der nĂ€chsten Abschnitte des Kurses eingefĂŒhrt und erlĂ€utert.
Wie schon im ersten Teil gesagt, werden die Programme mit TURBO-Pascal erstellt.
Die Programme laufen aber (falls nicht anders angegeben) auch auf anderen Pascal-Compilern.
Doch nun geht es richtig los: Wenn man an einer Stelle viele verschiedene FĂ€lle unterscheiden muĂ, so kann man dies mit einer geschachtelten if-then-else-Anweisung machen. Es gibt dafĂŒr jedoch einen viel leistungsfĂ€higeren Befehl, die CASE-Anweisung. Sie erlaubt es, mehrere FĂ€lle gezielt anzuspringen. Die Anweisung hat die Form:
CASE Ausdruck OF
Konstante 1 : Anweisung 1;
Konstante 2 : Anweisung 2;
...
Konstante n : Anweisung n
END
Die verschiedenen Anweisungen können dabei ĂŒbersichtlich untereinander geschrieben werden. Dadurch ergibt sich ein anschaulicheres Bild als bei einer geschachtelten if-then-else-Anweisung. Dies kann man auch am Struktogramm erkennen, das in Bild 1 dargestellt wird.
Das Programm (Listing 1) erwartet als Eingabe eine Ganzzahl zwischen eins und sieben. Es wird dann der entsprechende Wochentag ausgegeben. Wenn Sie das Listing eingegeben haben, sollten Sie sich damit ein wenig beschÀftigen. Probieren Sie einige Werte aus, auch solche, die nicht im angegebenen Bereich liegen.
program WOCHENTAG;
var Wochentag : integer;
begin
write ('Eingabe (1-7) : ');
readln (Wochentag);
if (Wochentag<8) and (wochentag>0) then
case Wochentag of
1: write ('Montag');
2: write ('Dienstag');
3: write ('Mittwoch');
4: write ('Donnerstag');
5: write ('Freitag');
6: write ('Samstag');
7: write ('Sonntag')
end
else write ('falsche Eingabeâ)
end.
Listing 1 & Struktogramm
Als Ausdruck ist bei der CASE-Anweisung eine Variable aller einfachen Typen erlaubt (z. B. INTEGER, CHAR, BOOLEAN usw). Nur der Datentyp REAL ist nicht zugelassen.
Die verwendeten Konstanten mĂŒssen alle vom selben Typ sein wie die Variable.
Vor einer Anweisung können auch mehrere Konstanten (durch Komma getrennt) stehen, falls mehrere Werte dieselbe Anweisung bedingen. Allerdings darf jede Konstante nur einmal innerhalb der Anweisung verwendet werden.
Wichtig ist bei der CASE-Anweisung auĂerdem, daĂ fĂŒr alle Werte, die die Variable annehmen kann eine entsprechende Konstante vorgegeben wird. Sollte dies nicht der Fall sein, so tritt ein Fehler auf. Um diese Fehlerquelle zu umgehen, kann man die Variable vor ihrer Benutzung in der CASE-Anweisung auf ihren Bereich hin kontrollieren. Dies wird mit einer einfachen if-Abfrage realisiert (siehe Listing 1 und Struktogramm). Mit einem zugefĂŒgten eise Zweig kann man dann alle anderen FĂ€lle behandeln.
Bei TURBO-Pascal ist das ELSE bereites als fester Bestandteil der CASE-Anweisung (siehe Bild 2) vorgesehen, dadurch entfĂ€llt die Abfrage mit IF. In manchen Pascal-Dialekten gibt es den Befehl OTHERS. Er ersetzt dann das eise. Eine vorangehende Abfrage mit âif ist auch hier nicht notwendig. Bei UCSD-Pascal und auch bei TURBO-Pascal tritt keine Fehlermeldung auf, wenn der Wert der Variablen keiner Konstanten entspricht. Es wird in diesem Fall mit der Programmanweisung, die hinter dem CASE-Block steht, fortgefahren.
Auffallend bei der CASE-Anweisung ist, daĂ sie mit einem END abgeschlossen werden muĂ, ohne ein BEGIN am Anfang zu benötigen.
Ein weiteres Beispiel fĂŒr die CASE-Anweisung ist in Struktogramm 2 dargestellt. Bei diesem Programm (Listing 2) wird nach Eingabe eines Buchstabens ein Name mit diesem Buchstaben ausgegeben. Hier wird erstmals der Datentyp CHAR verwendet. Die Variable âbuchstabeâ kann nun alphanumerische Zeichen annehmen. In diesem Fall sind jedoch nur die Buchstaben des Alphabets relevant. Sie werden im Programm immer in Hochkommas (z. B. buchstabe: = âaâ) gestellt, um sie von Variablen unterscheiden zu können.
Zur Veranschaulichung sind hier nur die Marken âaâ, âbâ, V, âdâ und âkâ belegt. Bei allen anderen wird der Text 'kein Name gespeichert!â ausgegeben. Zu diesem Zweck wird die Eingabe mit der IN-Operation kontrolliert. Sie hat die Form:
Variable IN [Menge]
Dabei muĂ natĂŒrlich der Datentyp der Variable mit dem der Menge ĂŒbereinstimmen. Da hier eine Menge von Buchstaben benötigt wird, muĂ die Variable als CHAR definiert sein.
Achtung: die IN-Funktion macht, wie auch die CASE-Anweisung, eine genaue Unterscheidung zwischen GroĂ-und Kleinbuchstaben. Man kann verzweifeln, wenn die Caps Lock Taste gedrĂŒckt ist und das Programm nicht erwartungsgemÀà reagiert.
Das Ergebnis ist vom Type BOOLEAN. Dieser Typ ist schon von anderen IF-Anweisungen her bekannt (siehe z. B. Listing 1) oder auch von der CASE-Anweisung im nĂ€chsten Programm. Das bedeutet, daĂ die Aussage die 'Werteâ false (falsch) und true (wahr) annehmen kann, je nachdem ob die Aussage wahr (Variable ist Teilmenge von Menge) oder falsch ist (Variable ist nicht Teilmenge von Menge).
program NAMEN;
var buchstabe : char;
begin
write ('Eingabe (a-z) : ');
readln (buchstabe);
if buchstabe in ['a',âb','c','d','k'] then
case buchstabe of
'a' : write ('Anton');
'b' : write ('Berta');
'c','k': write ('Claus/Klaus');
'd' : write ('Dora')
end
else write ('kein Name gespeichert!');
end.
Das dritte Beispiel zur CASE-Anweisung (Listing 3) setzt als Ausdruck den gerade besprochenen Typ Boolean ein. Als Konstanten bzw. Marken werden die Werte âtrueâ und âfalseâ eingesetzt. Je nachdem ob nun der Ausdruck âzahl>0â wahr oder falsch ist, wird zum entsprechenden Teil verzweigt.
Im nun folgenden Teil wollen wir uns mit den Möglichkeiten beschĂ€ftigen, die Pascal zur Schleifensteuerung anbietet. Diese Steuerbefehle sind fĂŒr die Programmierung von groĂer Bedeutung, weil sie es ermöglicht, eine Anweisung oder eine Folge von Anweisungen so lange zu wiederholen, bis eine vorher definierte Abbruchbedingung eintritt. Dies ist zwar prinzipiell auch mit einer EF-Abfrage und einem anschlieĂenden GOTO-Befehl erreichbar, doch ist diese Art der Schleifenbildung sehr unĂŒbersichtlich und fehler-anfĂ€llig. Bei Pascal hat man die Auswahl zwischen drei verschiedenen Schleifensteuerbefehlen. Dabei hat jeder Befehl seine Besonderheiten und somit seinen speziellen Anwendungsbereich. Die bekannteste Schleifenanweisung hat die Form:
FOR Variable : = Ausdruck 1 TO Ausdruck2 DO
bzw.
FOR Variable : = Ausdruck 1 DOWNTO Ausdruck2 DO
Diese Anweisung ist der aus Basic bekannten FOR-NEXT-Schleife Ă€hnlich. Ihr Struktogramm wird in Bild 2 dargestellt. Bei âDOWNTOâ zĂ€hlt die Schleife rĂŒckwĂ€rts.
Die Anzahl der Schleifenwiederholungen liegt in diesem Fall von Anfang an fest. So wird zum Beispiel die Schleife im Programm (Listing 4) zehnmal durchlaufen. Dabei wird immer der Wert der Schleifenvariable ausgegeben.
program FOR_Schleife;
var i : integer;
begin
for i:=1 to 10 do
writeln (i)
end.
Es sind folgende Regeln zu beachten:
- Ausdruck1 und Ausdruck2 können auch Variablen sein, deren Wert muà jedoch vor dem Eintritt in die Schleife festgelegt werden.
- Die Variable, Ausdruck1 und Ausdruck2 mĂŒssen vom selben Datentyp sein. Als Datentypen sind alle skalaren Typen (auĂer REAL) zugelassen, also INTEGER, CHAR und BOOT LAN.
- Wenn der Endwert schon am Anfang gröĂer ist als der Anfangswert (bzw. umgekehrt bei DOWNTO), so wird der Schleifeninhalt nicht bearbeitet. Das Programm lĂ€uft dann mit der Anweisung, die hinter dem Schleifenblock steht, weiter. Man nennt diese Form deshalb auch abweisende Schleife (siehe auch Bild 3).
- Die einzig mögliche Schrittweite ist 1 bzw. -1. Diese Festlegung hat neben ihrer EinschrĂ€nkung den Vorteil, daĂ bei einer Erhöhung der Schrittweite um Eins kein Rundungsfehler auftreten kann, wie dies in Basic hĂ€ufig der Fall ist. Wenn man eine andere Schrittweite benötigt, so muĂ man dafĂŒr eine separate Variable verwenden (z. B. Schrittweite: = i*0.1). Die Schleife legt dann nur die Anzahl der DurchlĂ€ufe fest.
- Die ZĂ€hlvariable kann innerhalb der Schleife fĂŒr Berechnungen benutzt werden. Ihr Wert darf jedoch nicht verĂ€ndert werden (z. B. i: = i*-2).
- Weder der Anfangs- noch der Endwert der Schleifenanweisung dĂŒrfen wĂ€hrend ihres Ablaufs verĂ€ndert werden.
- Der Wert der ZĂ€hlvariable ist nach dem Abarbeiten der Schleife nicht mehr verfĂŒgbar.
program ENTSCHEIDUNG;
var entscheidung : boolean;
zahl : real;
begin
write (â--- zahl>0----- â);
write ('Eingabe (1,0,-1);
readln (zahl);
case zahl>0 of
true: write ('--- wahrâ);
false: write ('--- falsch');
end;
end.
Bild 2 : CASE/ELSE - Abfrage
Die Punkte 5) - 7) treffen fĂŒr TURBO-Pascal nicht zu. Sie sind jedoch auch fĂŒr diese Anwender wichtig, um zum Beispiel Programme an andere Pascal-Versionen anpassen zu können. Wenn man die EinschrĂ€nkungen, die fĂŒr fast alle Pascal-Versionen gelten, nicht kennt kann es zu bösen Ăberraschungen kommen, wenn man auf einmal mit ihnen programmieren muĂ.
Das Beispielprogramm (Listing 5) verdeutlicht die Eigenarten von TURBO-Pascal. Es ist, in dieser Form, sonst nicht lauffÀhig!
Ansonsten stellt das Programm eine hĂ€ufig verwendete Form dar, nĂ€mlich eine geschachtelte Schleife. Schleifen können in beliebiger Anzahl ineinander verschachtelt werden. Sie dĂŒrfen sich dabei jedoch nicht ĂŒberschneiden. Dies wĂ€re bei der Darstellung mit Hilfe des Struktogramms auch nicht möglich (siehe Struktogramm 5).
Bild 3: abweisende Schleife
Wenn Sie sich das Listing nĂ€her betrachten, werden Sie feststellen, daĂ hier gegen viele Regeln aus âStandard-Pascalâ verstoĂen wird. So wird z. B. der Wert der ZĂ€hlvariable bei jedem Durchgang innerhalb der Schleife zusĂ€tzlich um Eins erhöht. Trotzdem kommt die Ă€uĂere Schleife nicht aus dem 'Trittâ. Sie lĂ€uft, wie am Anfang festgelegt 10 mal durch, obwohl i schon viel frĂŒher die Endbedingung (i = 10) erreicht hat (siehe Probelauf Bild 4).
Struktogramm 5
program FOR_TurboPascal;
var i,ende : integer;
begin
ende:=10;
for i:=1 to ende do
begin
writeln;
write (i : 2 );
i: = i + 1;
write (i:4);
for i:=1 to i do
write ('*');
end;
writeln;
write ('i nach Schleifenende-----> ',i )
end.
Listing 5
Compilation aborted
>
Compiling
20 lines
Code: 212 bytes (8257-832B)
Free: 25294 bytes (832C-E5FA)
Data: 11 bytes (E5FB-E606)
Running
1 2**
3 4****
5 6******
7 8********
3 10**********
11 12************
13 14**************
15 16****************
17 18******************
19 20********************
i nach Schleifenende â> 20
>
Bild 4: Probelauf
Auch die innere Schleife ist beachtenswert, denn es wird zum ZĂ€hlen und fĂŒr die Endbedingung dieselbe Variable i verwendet. Bei TURBO-Pascal spielt das keine Rolle. Die Endbedingung wird vor der AusfĂŒhrung der Schleife festgelegt und kann dann durch nichts mehr geĂ€ndert werden.
Auch nach dem Durchlaufen der Schleife ist die ZĂ€hlvariable noch verfĂŒgbar, das heiĂt, ihr Wert kann ausgedruckt oder weiterverarbeitet werden.
Im nÀchsten Teil geht es weiter mit den Kontrollstrukturen. Es wird die Struktur der REPEAT/UNTIL- und der WHILE/DO-Anweisung besprochen.