Einführung in die Programmiersprache PASCAL Teil 2

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

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:

  1. Ausdruck1 und Ausdruck2 können auch Variablen sein, deren Wert muß jedoch vor dem Eintritt in die Schleife festgelegt werden.
  2. 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.
  3. 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).
  4. 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.
  5. 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).
  6. Weder der Anfangs- noch der Endwert der Schleifenanweisung dürfen während ihres Ablaufs verändert werden.
  7. 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.



Aus: ST-Computer 03 / 1986, Seite 53

Links

Copyright-Bestimmungen: siehe Über diese Seite