Ein Pascalkurs für Computer-Anfänger
Willemers Informatik-Ecke

Ich fand diesen Kurs, den ich um 1990 gehalten habe, in meinen Unterlagen. Ich habe ihn gekürzt und in HTML übersetzt. Er umfasst nicht den kompletten Sprachumfang von PASCAL.

Einen PASCAL-Compiler findet man unter Linux als Paket fp-compiler in den Repositories. Der Compiler wird mit dem Befehl fpc aufgerufen.

PASCAL ist die Sprache der Entwicklungsumgebung Delphi. Als Nachfolger für Delphi gibt es das Projekt Lazarus, das mit dem Paket lazarus als Paket in den Linux-Repositories zur Verfügung steht.

Rahmen eines PASCAL-Programms

Ein PASCAL-Programm wird mit einer Art Textverarbeitung geschrieben und anschließend vom Compiler übersetzt. Ein minimales PASCAL-Programm sieht so aus:

PROGRAM Programmname;
BEGIN
END.

Die erste Zeile sagt dem Compiler, dass das Folgende kein Brief oder ähnliches ist, sondern ein Programm. Sie besteht aus dem festgelegten Wort PROGRAM, gefolgt von einem frei wählbaren Programmnamen. Er muss nur den PASCAL-Anforderungen für einen Namen entsprechen. Ein Name darf in PASCAL nur aus Buchstaben und Zahlen und dem Unterstrich bestehen, wobei als erstes Zeichen nur ein Buchstabe zulässig ist. Die deutschen Sonderzeichen sind in Namen nicht erlaubt. Direkt darauf folgt ein Semikolon. Man kann sagen, PASCAL liebt Semikolons. Es wird immer dann gesetzt, wenn Befehle oder Definitionen voneinander getrennt werden müssen. Alle Vereinbarungen - sogenannte Deklarationen - von Variablen und anderen Namen müssen zwischen der Zeile PROGRAM Name; und dem Wort BEGIN gemacht werden. Mit dem Wort BEGIN wird der ausführbare Teil des Programms angekündigt. Zu jedem BEGIN gehört immer ein Wort END. Dazwischen stehen die Befehle in der Reihenfolge, in der sie später ausgeführt werden. Am Ende eines Programmes muss ein Punkt hinter dem END stehen, damit der Compiler weiß, dass das Programm hier fertig ist.

PROGRAM Programmname;
(* Dieses Programm ist zum Probieren gedacht *)
VAR Name : String [30];
BEGIN
    Writeln ('Hallo, ich bin ein kleines PASCAL-Programm');
    Write ('Wie heisst Du? ');
    Readln (Name);
    Write (Name);
    Writeln (' ist ein schoener Name.');
END.

Kommentare

Es sind mehrere Dinge hinzugekommen. Die Sternklammern (* *) beinhalten Bemerkungen des Programmierers, in denen er schreiben kann, was er sich bei der Programmierung gedacht hat. Der Compiler wird den Inhalt dieser Klammern bei der Übersetzung außer Acht lassen.

Eingabe und Ausgabe

Betrachten wir, was das Programm wirklich tut. Dazu müssen wir die Befehle untersuchen, die hinter BEGIN stehen. Der Befehl Write schreibt den Inhalt der Klammern auf den Bildschirm. Der Befehl Writeln tut dasselbe, nur hängt er hinten einen Wagenrücklauf an. Sollen einfach nur Texte ausgegeben werden, werden diese in Hochkommata (Apostrophe) gesetzt, so wie einem Buch die wörtliche Rede in Anführungszeichen gesetzt wird.

Der nächste Befehl fordert den späteren Benutzer des Programmes auf, eine Eingabe zu machen. Readln heißt also: Warte und lese das, was auf der Tastatur eingetippt wird, bis die Wagenrücklauftaste gedrückt wird. Nun muss sich PASCAL irgendwie merken, was der Benutzer eingetippt hat. Dazu dient die Variable, die in Klammern hinter dem Readln steht.

Übung
Schreiben Sie ein Programm, das auf dem Bildschirm die beiden Worte "Hallo Benutzer" ausgibt.

Variablen und Variablentypen

Am Anfang des Programms steht die Zeile:

VAR Name : String [30];

Das bedeutet, dass sich PASCAL ein Stück Speicher reserviert, das ausreicht, um 30 Buchstaben zu speichern. Es findet diesen Speicher unter dem Begriff Name wieder. Sollten die rechteckigen Klammern auf der Tastatur nicht verfügbar sein, kann stattdessen auch String(.30.) geschrieben werden. Das Programm erzeugt auf dem Bildschirm:

Hallo, ich bin ein kleines PASCAL-Programm
Wie heisst Du?

Das Programm wartet nun auf die Eingabe des Benutzers.

Wie heisst Du? Anna
Anna ist ein schoener Name.

Die Buchstaben Anna sind nun in dem Speicherplatz mit dem Namen Name abgelegt worden und durch den Befehl Write (Name) wieder auf dem Bildschirm ausgegeben worden.

Übung
Geben Sie das oben gezeigte Programm ein, übersetzen Sie es und lassen Siees ein paarmal laufen. Probieren Sie, die verschiedensten Vornamen einzugeben.

Variablen sind Speicherbereiche, die reserviert werden, um die Zahlen, Buchstaben oder Buchstabenketten (auch String genannt) für den späteren Gebrauch im Programm zu speichern. Da ein Buchstabe anderen Platz braucht als eine Fließkommazahl, wird in PASCAL jede Variable vor Benutzung bezeichnet. Für die Praxis und unseren Kurs sind die folgenden vier Variablenarten (auch Typen genannt) ausreichend.

Typ-Bezeichnung Inhalt
INTEGER ganze Zahlen von -32768 bis 32767
REAL Fließkommazahlen. Das Komma im Deutschen entspricht in der englisch sprechenden Welt einem Punkt.
CHAR kann einen Buchstaben aufnehmen
String[10] kann eine Buchstabenkette (Wort oder Satz) von maximal 10 Zeichen aufnehmen.

Achtung: Der Typ String ist kein Standard-PASCAL, ist aber bei den meisten PASCAL-Compilern so verfügbar.

Übung
In einem Programm soll für jede Variablenart eine Variable angelegt werden und für jede Variable ein Wert eingegeben und danach wieder ausgegeben werden. Das Programm sollte dem Benutzer vorher sagen, was für eine Eingabe er machen soll (ganze Zahl, Buchstaben, etc.).

Nach der Übung fällt auf, dass die REAL-Werte merkwürdig aussehen (Statt 12,95 steht auf dem Bildschirm 1.2950000000E+1). Diese Darstellung wird Exponentialschreibweise genannt. Die Zahl hinter dem E ist der Exponent zur Basis 10. Man kennt diese Darstellung ganz ähnlich auf einigen Taschenrechnern. Als Faustregel zum Lesen solcher Zahlen gilt: Das Komma (in PASCAL also der Punkt) wird um die Zahl hinter dem E nach rechts verschoben. In den meisten Fällen ist es aber sinnvoller, die gewohnte Art der Darstellung zu erhalten. Dazu wird beim Write bzw. Writeln hinter die Variable :8:2 geschrieben. Dies bewirkt, dass für die Ausgabe insgesamt acht Stellen freigehalten werden, von denen 2 für die Nachkommastellen verwendet werden.

Übung
PRODUKT: Schreiben Sie ein kleines Programm, das für ein Produkt den Namendes Produkts und den Preis des Produkts vom Benutzer einliest. Danach sollauf dem Bildschirm erscheinen: Das Produkt ... kostet ... DM.

Arithmetik

Die Zuweisung

Gerechnet wird in Pascal, indem einer Variablen das Ergebnis einer Berechnung zugewiesen wird. Das Zuweisungssymbol ist :=. Die Anweisung a:=b weist der Variablen a den Inhalt der Variablen b zu. a und b müssen dabei immer vom gleichen Typ sein. Ausnahmen finden sich im Kapitel Typumwandlungsfunktionen.

Addition, Subtraktion und Multiplikation

Neben der Zuweisung eines Ergebnisses, gibt es auch die Möglichkeit, das Ergebnis einer Berechnung direkt per Writeln auf dem Bildschirm darzustellen. In jedem Fall muß die Art der Berechnung durch Operatoren (+,-,*) angegeben werden.

+ Addieren zweier Werte. Bsp: Summe:=Summand + 12;
* Multiplizieren zweier Werte. Bsp: Betrag:=Preis * Stueckzahl;
- Subtrahieren zweier Werte. Bsp: Tara:=Brutto - Netto;

Zwei Arten der Division

Bei der Division unterscheiden sich die Möglichkeiten der beiden Datentypen. REAL ist in der Lage auch einen Bruch aufzunehmen. Dementsprechend lautet die Division für REAL-Variablen:

/ Division. Bsp: Verbrauch:=Benzin / Kilometer;

Bei INTEGER-Variablen ist es schon schwieriger. Eine Darstellung von 3.5 als Ergebnis geht nicht. Also wird bei der Division nur der ganzzahlige Anteil zum Ergebnis. Dafür gibt es einen weiteren Operator, der den Rest einer Zahl ausweist, der nicht mehr aufzuteilen ist.

DIV Division. Bsp: Ergebnis:= 7 DIV 2; Das Ergebnis lautet 3!
MOD Rest einer Division. Bsp: Rest:= 7 MOD 2; Das Ergebnis ist der Rest der Division von 7 und 2, nämlich 1.

Typumwandlungsfunktionen

Werden Variablen verschiedenen Typs miteinander verknüpft, müssen in PASCAL die Typen einander angeglichen werden. Es muß also ein Typ in einen anderen verwandelt werden. Die folgenden Umwandlungen sind wichtig:

INTEGER nach REAL
Hierzu ist kein Befehl erforderlich. Pascal macht dies automatisch, wenn es erforderlich ist. Es gibt hier auch keine Probleme, da jede INTEGER-Zahl eine äquivalente REAL-Zahl aufweist.

REAL nach INTEGER
Bei der Umwandlung einer REAL-Zahl in eine ganze Zahl verliert der Wert an Information. PASCAL fordert vom Programmierer, anzugeben, wie das geschehen soll. Zwei Möglichkeiten gibt es:

TRUNC(Wert)
Die Nachkommastellen werden abgeschnitten.
ROUND(Wert)
Dies entspricht dem kaufmännischen Runden. Steht nach dem Komma eine Ziffer von 5 bis 9, so wird der Vorkommawert um eins erhöht.

INTEGER nach CHAR
Funktion CHR(48) erzeugt den Buchstaben '0'.

CHAR nach INTEGER
Funktion ORD('A') erzeugt die Zahl 65.

Weitere arithmetische Operationen

Es gibt noch einige arithmetische Operationen. So sind schon im Standard-PASCAL Funktionen wie Sinus (SIN(x)) oder Wurzeln (SQRT(x)) definiert. Es macht für eine Einführung wenig Sinn, sich in dieses Gebiet zu vertiefen, da der Normalanwender diese mathematischen Funktionen selten braucht. Bei Bedarf sei auf die weitergehende Literatur und die Handbücher der jeweiligen Implementation von PASCAL verwiesen.

Übung
Programm MULTI, das vom Benutzer zwei Zahlen einliest, diese miteinander multipliziert und das Ergebnis ausgibt. Wer schneller fertig ist, soll das Programm auf Addition, Subtraktion und Division ändern.
PRODUKT: Erweitern Sie das Programm dahingehend, daß nun zusätzlich dieMenge der Produkte angegeben wird und der Preis dieser Menge ausgegebenwird. Letztlich kann auch die MWSt aufgeschlagen werden. Schnellere Schülerkönnen die MWSt auch vom Benutzer angeben lassen.

Befehle zu Programmsteuerung

Unterscheidungen

Es ist oft notwendig, auf bestimmte Situationen unterschiedlich zu reagieren. Nehmen wir als Beispiel die Eingabe der Preise bei der Aufnahme einer Bestellung. Es ist Unsinn, negative Preise zuzulassen. Obwohl negative Stückzahlen auch nicht sinnvoll sind, kann diese Möglichkeit noch sinnvoll sein, um auch Reklamationen bearbeiten zu können. Ein solche Unterscheidung hat grundsätzlich folgenden Aussehen:

Wenn der Preis positiv ist
    errechnen wir den Gesamtpreis
Andernfalls
    hat der Benutzer ein falsche Eingabe gemacht

Der Andernfalls-Zweig kann auch weggelassen werden. Die Pascal-Notation ist:

IF Bedingung THEN Tuwas ELSE Tuanderes;

Wichtig ist hier, daß vor dem ELSE kein Semikolon steht. Da ein Semikolon immer zwei Anweisungen trennt, würde ein Semikolon an dieser Stelle den ELSE-Zweig vom dazugehörigen IF trennen. Das obige Beispiel als PASCAL-Programmteil:

IF Preis >= 0 THEN
    Gesamt:=Gesamt+Preis
ELSE
    Writeln ('Falsche Eingabe...');

Reicht ein Befehl nicht aus, können auch mehrere Befehle angegeben werden. Sie müssen dann mit BEGIN und END eingeklammert werden, um PASCAL zu zeigen, daß diese Befehle zusammengehören. Bsp.:

IF Menge<0 THEN
BEGIN
  Writeln ('Eine negative Menge ist ja wohl das Letzte!');
  Writeln ('Was haben Sie zu Ihrer Rechtfertigung zu sagen?');
  Readln (Lassihnschwaetzen);
  Writeln;
  Writeln ('Das ist ja wohl eine dumme Ausrede!');
END;

Um zwei Werte zu vergleichen, gibt es folgende Symbole:

= der erste Wert muß gleich dem zweiten sein.
< > der erste Wert muß ungleich dem zweiten sein.
< der erste Wert muß kleiner als der zweite sein.
> der erste Wert muß größer als der zweite sein.
< = der erste Wert muß kleiner als der zweite sein oder die Werte müssen gleich sein.
> = der erste Wert muß größer als der zweite sein oder dier Werte müssen gleich sein.

Übung
Es soll das Programm MULTI geändert werden, so daß nur positive Zahlen berechnet werden.
PRODUKT: Das Programm soll nur den Gesamtpreis berechnen, wenn der Preis nicht negativ ist.

Schleifen

Es reicht nicht, unter einer Bedingung eine Unterscheidung zu treffen. Es müssen häufig Dinge mehrfach ausgeführt werden. Diese Konstruktion wird in der EDV Schleife genannt. Bei jeder Schleife muß eine Abbruchbedingung formuliert werden, da sonst ein Programm nicht zum Ende kommt. Ein Fehler in dieser Bedingung führt zu der gefürchteten Endlosschleife.

REPEAT UNTIL

Ein Programm sollte nicht gleich aufgeben, nur weil der Benutzer sich einmal vertan hat. Man sollte ihm die Möglichkeit der Verbesserung lassen. Im folgenden soll der Benutzer den Preis solange eingeben, bis er eine positive Zahl eingegeben hat.

Wiederhole
    Benutzer soll Preis eingeben
bis Preis positiv ist

In PASCAL hat eine solche Konstruktion folgendes Aussehen:

REPEAT
    Write ('Was darf's kosten? ');
    Readln (Preis);
UNTIL Preis>=0;

Die Befehle zwischen REPEAT und UNTIL werden wiederholt, bis die Bedingung hinter UNTIL zutrifft. Ein solches Konstrukt wird Schleife genannt.

Übung
PRODUKT: Lassen Sie nun den Benutzer den Preis so lange eingeben, bis dieser positiv ist. Die Schnelleren können dieselbe Schleife für die Abgabemenge machen.
Das Programm ZAEHL soll zählen. Der Benutzer soll zu Anfang eingeben, wie weit gezählt werden soll. Danach sollen alle Zahlen untereinander auf dem Bildschirm ausgegeben werden. Wer schneller fertig ist, soll auch den Anfangswert vom Benutzer erfragen.
Das Programm RATE soll ein kleines Spiel sein. Der Benutzer gibt solange eine Zahl an, bis er die im Programm vorgegebene Zahl errät.

FOR TO DO

Bei der Übung ZAEHL müssen drei Dinge beachtet werden:

Jeder dieser Punkte ist eine Fehlerquelle, die zu der gefürchteten Endlosschleife führen kann. Eine Endlosschleife ist eine Schleife, in die Endebedingung nie eintritt und so niemals aufhört zu laufen.

Da das Abzählen häufiger benötigt wird, gibt es eine besondere Schleife zu diesem Zweck. Diese wird aus den oben gezeigten Bestandteilen aufgebaut:

FOR Variable :=Startwert TO Obergrenze DO TuWas

Immer dann, wenn etwas eine bestimmte Anzahl von Wiederholungen hat oder wenn etwas durchgezählt wird, wird diese Schleife die erste Wahl darstellen. Innerhalb einer Schleife enthält die Variable den aktuellen Wert.

Das Programm ZAEHL sieht bei Zuhilfenahme der FOR-Schleife so aus:

PROGRAM ZAEHL;
VAR i, Endzahl : INTEGER;
BEGIN
    Write ('Wie weit soll ich zaehlen?');
    Readln(Endzahl);
    FOR i:=1 TO Endzahl DO
        Writeln(i);
END.

Wie schon beim IF ist nur ein Befehl standardmäßig beim FOR anzugeben. Soll über mehrere Befehle geschleift werden, kann wiederum eine BEGIN END Klammerung benutzt werden.

Übung
Schreiben Sie ein Programm, das die Summe der ersten einhundert Zahlen errechnet (also 1 + 2 + 3 + 4 ...).
Schreiben Sie ein Programm ZINSESZINS, das eine Zinseszinstabelle für die nächsten zehn Jahre erstellt. Links in jeder Zeile steht das Jahr, rechts steht das derzeitige Kapital inkl. Zinsen.

WHILE DO

Die Schleifenform WHILE DO ergänzt PASCAL dahingehend, daß die Bedingung am Anfang der Schleife steht. Da für unsere Zwecke die REPEAT UNTIL Schleife ausreicht, wird hier nicht weiter auf die WHILE DO Schleife eingegangen.

Kombination mehrerer Konstrukte

Eine Verschachtelung mehrerer Schleifen und Unterscheidungen sind möglich. So ist es möglich, nur unter einer bestimmten Bedingung zu wiederholen oder auch mehrere Schleifen ineinander zu schachteln, wenn z. B. für mehrere Produkte die Preise eingegeben werden sollen und jede einzelne Eingabe so lange wiederholt werden soll, bis der Preis positiv ist. Ein anderes Beispiel soll hier vorgeführt werden. Es ist bewußt recht komplex gehalten.

Zur Ermittlung der Gesamtpunkte eines Schülers muß für jede Aufgabe (FOR-Schleife) ein Punktewert eingegeben werden. Die Eingabe des Punktwerts wird solange wiederholt, bis er positiv wird (REPEAT-Schleife). Der Punktewert wird nur aufsummiert, wenn er positiv ist (IF-Unterscheidung). Andernfalls erscheint auf dem Bildschirm eine Warnmeldung (ELSE-Zweig).

PROGRAM Klassenarbeit;
VAR i, Aufgaben : INTEGER;
    Gesamtpunkte, Punkte : INTEGER;
BEGIN
    Write ('Anzahl der Aufgaben: '); Readln (Aufgaben);
    Gesamtpunkte:=0;
    FOR i:=1 TO Aufgaben DO BEGIN
        REPEAT
            Write ('Aufgabe Nr. '); Write (i); Write (': ');
            Readln (Punkte);
            IF Punkte>=0 THEN
                Gesamtpunkte:=Gesamtpunkte + Punkte
            ELSE
                Writeln('Nur positive Punkte...');
        UNTIL Punkte>=0;
    END; (* FOR *)
    Writeln; Write ('Der Schueler hat ');
    Write (Gesamtpunkte);
    Writeln (' Punkte');
END.

Übung
Das Programm ZINSESZINS soll geändert werden, daß es den Zinseszins nur alle zehn Jahre anzeigt. Wer schneller fertig ist, prüft, ob die Jahreszahl positiv ist oder läßt den Benutzer angeben, in welchem Jahresabstand die Ausgabe erfolgen soll.
Das Programm PRODUKT soll so erweitert werden, daß bei der Eingabe eines negativen Preises eine Warnmeldung erscheint, die den Benutzer zur Neueingabe auffordert.
Ergänzen Sie das Programm RATE dahingehend, daß nach jedem Rateversuch des Benutzers auf dem Bildschirm ausgegeben wird, ob er zu hoch oder zu niedrig geraten hat.

Logische Verknüpfungen

Wie man sieht kann man auf den Wert bestimmter Variablen hin den Programmfluß beeinflussen. Manchmal gibt es aber Fälle, die nicht nur von dem Zustand einer Variablen, sondern von mehreren Bedinungen abhängen. Wir kennen dies im täglichen Leben auch. So darf man nur Autofahren, wenn man einerseits einen Führerschein hat und andererseits nicht betrunken ist.

UND

Wenn sowohl eine Bedingung als auch eine weitere eintreten muß, kann man dies mit AND (engl. und) verknüpft werden. Insbesondere wenn eingegrenzte Bereiche betrachtet werden sollen, ist die AND-Verknüpfung zu benutzen. In PASCAL wird dies wie folgt notiert:

IF (Preis>100) AND (Preis<500) THEN
    Writeln ('Der Preis ist in Ordnung')
ELSE
    Writeln ('Extremer Preis');

Es ist zu beachten, daß der ELSE-Zweig sowohl erreicht wird, wenn der Preis höchstens 100, als auch, wenn der Preis mindestens 500 beträgt. Es fällt bei der Betrachtung auf, daß die einzelnen Bedingungen geklammert sind. Dies ist grundsätzlich bei allen logischen Verknüpfungen erforderlich.

Es können natürlich auch verschiedene Variablen verknüpft werden. So könnte man eine Bedinung, die aussagt, daß ein Produkt nur gekauft wird, wenn der Preis höchstens 1000 beträgt und der Etat mindestens 2000 beträgt, so formulieren:

IF (Preis<=1000) AND (Etat>=2000) THEN
    Writeln ('Kaufen')
ELSE
    Writeln ('Stehenlassen');

ODER

Reicht mindestens eine von mehreren Bedingungen aus, so wird dies in PASCAL mit dem Wort OR (engl. oder) beschrieben. Die Bedingung trifft zu, wenn eine von beiden Teilbedingungen zutrifft oder wenn beide zutreffen. Es entspricht also nicht dem Entweder-Oder.

Die Oder-Verknüpfung wird häufig im Zusammenhang mit Schleifen gebraucht, die nicht nur bei Ende der Arbeit, sondern auch durch Benutzerabfrage beendet werden können. So könnte z. B. bei einem Computerspiel, das nach 100 Sekunden aufhört, sofern es nicht vom Spieler durch Drücken der Taste Q abgebrochen wurde, eine Schleife aufweisen, die wie folgt aussieht:

REPEAT
 ....
UNTIL (Sekunden>=100) OR (Taste='q');

Auch die Abfrage mehrerer Tasten ist ein typisches Oder-Problem. So sieht die Abfrage, die neben dem kleinen q auch das große Q zuläßt wie folgt aus:

   IF (Taste='q') OR (Taste='Q') THEN ....

NICHT

Soll das Gegenteil einer Bedingung betrachtet werden, kann die Gesamtbedingung geklammert werden und ein NOT vorangestellt werden. Nicht immer ist die Umsetzung einer Bedingung trivial. So ist noch klar, daß das Gegenteil von Tage > = 20 Tage < 20 ist. Dagegen erfordert die Negierung der folgenden Zeile einiges Nachdenken.

IF (Gehalt>=1000) AND (Gehalt<3000) THEN ...

Das Gegenteil der einzelenen Bedingungen ist noch klar. Statt > = wird < , statt < wird > = verwendet. Aber auch das AND kann nicht so stehenbleiben, da sonst das Gehalt sowohl kleiner als 1000 als auch mindestens 3000 sein muß. Offensichtlich geht das nicht. Die richtige Verknüpfung ist hier OR.

IF (Gehalt<1000) OR (Gehalt>=3000) THEN ...

Datentyp Felder (ARRAY)

Häufig gibt es in der Praxis das Problem, daß nicht nur ein Wert gespeichert werden muß, sondern daß von einer Art mehrere Exemplare vorliegen. Zum Beipiel wird ein Versandhaus viele Produkte verkaufen, ein Hotel hat viele Zimmer und so fort. Wenn mehrere Exemplare derselben Sorte vorliegen, kann man diese durchnumerieren und mit Hilfe seiner Nummer ansprechen. So hat zum Beispiel ein Hotel für jedes Zimmer eine Nummer. Wenn ich die Zimmernummer kenne, kann ich in der Belegungsliste nachschlagen, wer dort wohnt.

Um dies auch in Pascal nachbilden zu können, kann man ein sogenanntes ARRAY anlegen. Man benennt die Variable und definiert sie als ARRAY ihres Typs:

VAR Variable : ARRAY [1..20] OF Typ ;

Wir wollen als Beispiel einen Händler betrachten, der die Preise seiner Produkte gern gespeichert hätte und auf die Produktnummer immer gern den Preis ausgegeben hätte. Zu Anfang muß für jedes Produkt der Preis angegeben werden. Beim Verkauf muß er nur noch die Nummer eingeben und er sieht den Preis auf dem Bildschirm.

PROGRAM Produkt;
VAR Preis : ARRAY [1..20] OF REAL;
    i, Anzahl, Nummer : INTEGER;
BEGIN
    (* Eingabe aller Produktpreise *)
    Write ('Wieviele Produkte: '); Readln (Anzahl);
    FOR i:=1 TO Anzahl DO BEGIN
        Write ('Produkt '); Write (i); Write (' kostet: ');
        Readln (Preis[i]);
    END; (* FOR *)
    (* Der Verkauf beginnt... *)
    REPEAT
        Write ('Produktnummer: ');
        Readln (Nummer);
        IF Nummer>0 THEN BEGIN
            Write ('Produkt '); Write (Nummer);
            Write (' kostet '); Writeln (Preis[Nummer]);
        END; (* IF *)
    UNTIL Nummer=0;
END.

Übung
Ergänzen Sie das Programm Produkt so, daß auch die Namen der Produkteerfaßt werden.

Eigentlich kennen wir bereits von Anfang an solche ARRAYs. Der Typ String hat am Ende auch die rechteckigen Klammern, die darauf hinweisen, daß dies einmal ein Array gewesen ist.

String[20] entsprach ARRAY [1..20] OF CHAR

Ursprünglich war PASCAL auch so definiert, daß Zeichenketten auf diese Weise bearbeitet werden mußten. Dies hat man geändert, da Readln und Writeln sonst selbst programmiert werden müßten.

Übung
Schreiben Sie ein Programm HOTEL, das die Zimmerbelegung eines Hotels verwaltet. Das Hotel hat 10 Zimmer. Ein leeres Zimmer wird durch eine Reihe von Minuszeichen markiert. Der Benutzer bekommt nach jeder Eingabe die Zimmerbelegung ausgegeben. Er kann eine Zimmernummer, dann den neuen Namen eingeben. Dies wird als neue Belegung eingetragen und der Benutzer erhält wieder die Zimmerbelegung. Bei Eingabe der Zimmernummer 0 wird das Programm beendet.

Unterprogramme (PROCEDURE)

Prozeduren bieten die Möglichkeit, mehrere Befehle zu einer Aufgabe zusammen zu fassen und sie wie einen neuen Befehl aufzurufen. Man kann also seine eigenen Befehle definieren und später beliebig oft aufrufen.

Als erstes überlegt man sich einen Namen für den neu zu schaffenden Befehl. Anschließen wird ein kleines Programm erstellt, das genau die Befehle enthält, die unser neuer Befehl beherrschen soll. Die neue Prozedur hat einen ganz ähnlichen Aufbau wie ein PASCAL-Programm, nur daß es PROCEDURE statt PROGRAM heißt. Aus diesem Grund werden Prozeduren auch oft Unterprogramme genannt.

PROGRAM Sterne;

VAR i: INTEGER;
    Sternzahl : INTEGER;

PROCEDURE MachVieleSterne;
VAR i: INTEGER;
BEGIN
    FOR i:=1 TO Sternzahl DO
        Write('*');
    Writeln;
END;

BEGIN (* Hier beginnt der Ablauf des Programms *)
    Writeln ('Viele, viele Sterne.....');
    Sternzahl:=77;
    FOR i:=1 TO 10 DO
        MachVieleSterne;
END.

Die Prozeduren werden nach der Variablendeklaration und vor dem BEGIN des Hauptprogramms definiert. Die Definition der Prozedur MachVieleSterne bewirkt selbst noch keine Aktivitäten. Erst bei Aufruf des Befehls MachVieleSterne startet die Prozedur. Es werden also 10 Zeilen mit je 77 Sternen ausgegeben.

Interessant ist auch die Benutzung der Variablen i. Die Prozedur hat ihre eigene private Variable i. Dadurch wird die Variable i des Hauptprogramms nicht verändert. Beide Schleifen stören einander nicht. Eine Variable, die von Unterprogramm und Programm benutzt wird, stellt Sternzahl dar. Im Hauptprogramm wird so festgelegt, wieviele Sterne je Zeile erscheinen soll. Aus Sicht der Prozedur nennt man i eine lokale und Sternzahl eine globale Variable. Eine lokale Variable wird nach dem Verlassen einer Prozedur wieder vergessen. Sie dient also nur der kurzzeitigen Speicherung.

Übung
PRODUKT: Die Eingabe eines Produkts ist langsam zwar komfortabler, aber auch unübersichtlicher geworden. Es wird ein Produktname eingegeben und ein Preis. Der Preis wird geprüft ob er positiv ist. Wir können uns nun einen Befehl definieren, der dieses alle tut.
Zinseszinstabelle: Die Eingabe wird als Prozedur erstellt. Wer schneller ist, baut die Berechnung und Ausgabe zu einer Prozedur um. Damit sollte im Hauptprogramm nur noch Eingabe, Verarbeitung, Ausgabe stehen.

Top-Down-Programmierung

Wir betrachten das Beispiel eines Straßenhändlers, der Sandalen und die durch die Benutzung der Sandalen später benötigte Fußsalbe verkauft. Am Morgen legt er aus den Erfahrungen des letzten Tages oder in Abhängigkeit vom Wetter den jeweiligen Preis für die Salbe und für die Sandalen fest. Es kommen nun Leute und kaufen x Sandalen und y Tuben Fußsalbe. Der Computer soll die Summe für die Leute an der Kasse errechnen und am Abend den Umsatz auswerfen.

Preise festlegen
Wiederhole
Einkaufsmenge eines Kunden
Kundenrechnung erstellen
Benutzer fragen, ob schon Feierabend ist
bis Benutzerantwort = 'j'
Umsatz auswerfen



Aus diesem Ablaufplan wird direkt ein Hauptprogramm in PASCAL geschrieben:

PROGRAM Strassenverkaeufer;
VAR Antwort : CHAR;
(* Variable wird fuer die Antwort des Benutzers auf die Frage nach
   Ende des Programms gebraucht. *)
BEGIN
    PreiseEingeben;
    REPEAT
        VerkaufsMengeEingeben;
        KundenRechnung;
        IstSchonFeierabend;
    UNTIL Antwort='j';
    UmsatzAuswerfen;
END.

Es müssen nun die Prozeduren PreiseEingeben, VerkaufsMengeEingeben, KundenRechnung, IstSchonFeierabend und UmsatzAuswerfen geschrieben werden. Dabei stellt sich heraus, daß die Prozeduren PreiseEingeben, VerkaufsMengeEingeben und IstSchonFeierabend jeweils nur aus einem Write und einem Readln bestehen. Die eingelesenen Variablen müssen bei Benutzung jeweils oben angegeben werden. Die Prozedur KundenRechnung ist etwas anspruchsvoller, aber nicht problematisch:

PROCEDURE KundenRechnung;
VAR KassenWert: REAL;
BEGIN
    KassenWert:=SandalenMenge * SandalenPreis;
    KassenWert:=KassenWert + (SalbenMenge * SalbenPreis);
    Write ('Der Kunde schuldet: ');
    Writeln (KassenWert);
END;

Lediglich bei der Umsatzberechnung muß nochmal etwas überlegt werden. Der Umsatz muß zu Anfang des Tages Null sein. Bei jedem Verkauf muß der berechnete Betrag zum Umsatz dazugeschlagen werden. Am Ende muß der Umsatz ausgeworfen werden. Die Lösung besteht darin, eine globale Variable Umsatz zu definieren, dieser nach dem BEGIN oder in PreisEingaben den Wert 0 zuzuweisen, in KundenRechnung den KassenWert durch Umsatz:=Umsatz + KassenWert; aufzuschlagen und in der Prozedur UmsatzAuswerfen diese Variable mit Writeln auf dem Bildschirm auszugeben.

Übung
Das Program BUCHHANDEL soll einen Buchverkäufer unterstützen, der nur ein Buch verkauft. Am Anfang des Tages legt er den heutigen Preis seines Buches fest. Im Laufe des Tages kommen Kunden und kaufen Bücher. Es soll nur die Menge der Bücher eingegeben werden und das Programm soll den Preis bestimmen.

Verbunde (RECORD)

Wir haben bisher für jedes Produkt zwei unabhängige Variablen gehabt. Aber Preis und Name eines Produkts gehören ja gemeinsam zu einem Produkt. Es kann vielleicht noch der Vorrat im Lager zum Produkt gehören. Dazu kann ein Produkttyp erzeugt werden.

TYPE
     ProduktTyp = RECORD
            Name   : String [30];
            Preis  : REAL;
            Vorrat : REAL;
          END;

VAR Produkt : ProduktTyp;

BEGIN
    ReadLn (Produkt.Name);
    ReadLn (Produkt.Preis);

Man kann die Variablenarten wie INTEGER, REAL und String durch eigene Typarten ergänzen. Dazu wird mit TYPE ein neuer Typname vereinbart und hinter dem Gleichheitszeichen definiert, wie dieser aussieht. Zwischen RECORD und END werden Verbunde definert. Es werden jeweils die Bestandteile aufgeführt und wie bei der Variablendeklaration hinter einem Doppelpunkt der Typ geschrieben. Die Namen vor dem Doppelpunkt dienen dem späteren Zugriff auf die einzelnen Bestandteile. In Variablendeklaration ist leicht zu erkennen, daß die Definition einer Variablen mit dem eigenen Typ genauso funktioniert, wie mit den Standardtypen. Hinter dem BEGIN ist beispielhaft zu sehen, wie auf einen solchen Verbund zugegriffen wird. Es wird zuerst der Variablenname genannt. Dann wird ein Punkt gesetzt, als Zeichen dafür, daß auf die Unterstruktur zugegriffen wird und als letztes wird der Name der Unterstruktur genannt, wie er in der Typdefinition aufgeführt ist.

Übung
Es wird ein leeres Programm erstellt, in dem der Typ Datum definiert wird. Ein Datum muß aus einem Tag, Monat und einem Jahr bestehen. Es sollen von diesem Typ die Variablen heute, morgen und uebermorgen deklariert werden. Das Datum soll dann einmal eingegeben und anschließend wieder auf den Bildschirm geschrieben werden.

Komplexere Typen können aus einfacheren Typen zusammengesetzt werden. Zum Beispiel:

TYPE
     Person = RECORD
                Name : String[20];
                Wohnung : Adresse;
                geboren : Datum;
              END;

Pascal kennt nun weder Datum noch Adresse. Also muß vor der Definition von Person ein Typ Datum und ein Typ Adresse definiert werden. Wie das Datum erstellt wird wurde schon in der Übung gesehen. Der Typ Adresse könnte nun so aussehen:

TYPE
     Datum   = RECORD
                 Tag, Monat, Jahr : INTEGER;
               END;

     Adresse = RECORD
                 Strasse : String[20];
                 PLZ : INTEGER;
                 Ort : String[20];
               END;

     Person  = RECORD
                 Name : String[20];
                 Wohnung : Adresse;
                 geboren : Datum;
               END;

VAR Meier, Mueller : Person;

Das Ausgeben des Wohnorts der Person Mueller würde so aussehen:

    Writeln (Mueller.Wohnung.Ort);

Es wird also dem Variablennamen ein Punkt nachgestellt. Danach folgt das Objekt unter dem Namen, der in der Typendefinition benutzt wird. Ist auch dieses wieder ein RECORD wird wiederum der Name aus dieser Typendefinition benutzt.

Mischen von Typenkonstrukten

Wir hatten schon gesehen, wie man Produkte mit Hilfe von RECORDs modelliert. Wir hatten auch gesehen, wie man viele Preise mit Hilfe eines ARRAYs speichern kann. Für einen Händler ist es interessant, von dem modellierten Produkt ein ARRAY zu bilden, um z. B. eine Produktpalette darstellen zu können. Dazu wird erst ein Produkt modelliert und davon ein ARRAY definiert. Wir sehen dies in folgendem Beispiel:

PROGRAM Bestellungen;
TYPE
    ProduktTyp = RECORD
                   Name   : String [30];
                   Preis  : REAL;
                   Vorrat : REAL;
                 END;

    PalettenTyp = ARRAY[1..200] OF ProduktTyp;

VAR Produkt : PalettenTyp;

Es soll nun im Beispiel auf dem Bildschirm der Name, der Preis und der Vorrat des Produktes Nummer 27 ausgegeben werden. Dazu müssen im Programm folgende Befehle gegeben werden:

    Writeln (Produkt[27].Name);
    Writeln (Produkt[27].Preis:8:2);
    Writeln (Produkt[27].Vorrat:8:0);

Übung
Schreiben Sie eine Schleife, die für die ersten fünf Produkte den Namen, den Preis und den Vorrat von der Tastatur einliest.

Prozeduren mit Parametern

Um eine Prozedur für mehrere Objekte benutzen zu können, müßte es möglich sein, ihr zu sagen, daß sie eine beliebige Variable dieses Typs benutzen kann. So könnte man Befehle schreiben, die sich wie Pascal-Befehle verhalten. Das heißt, daß unser Befehl nur enthält, wie er seine Arbeit durchführen soll, aber nicht, mit welchen Variablen. Die Variablen werden ihm später bei Benutzung übergeben. Dies alles hört sich erst mal kompliziert an, aber nichts anderes haben wir die ganze Zeit benutzt:

PROGRAM Ausgabe;
VAR EineZahl, NochNeZahl: INTEGER;
BEGIN
    Writeln (EineZahl);
    Writeln (NochNeZahl);
END.

Wir sind ganz selbstverständlich davon ausgegangen, daß Writeln selbst weiß, daß es in der ersten Zeile die Variable EineZahl und in der zweiten Zeile NochNeZahl ausgeben soll. Wir wollen die uns bekannte Prozedur MachVieleSterne nun so erweitern, daß man ihr beim Aufruf sagen kann, wieviele Sterne sie produzieren soll.

PROGRAM Sterne;

VAR i: INTEGER;

PROCEDURE MachVieleSterne (SternZahl: INTEGER);
VAR i: INTEGER;
BEGIN
    FOR i:=1 TO Sternzahl DO
        Write('*');
    Writeln;
END;

BEGIN (* Hier beginnt der Ablauf des Programms *)
    Writeln ('Viele, viele Sterne.....');
    MachVieleSterne(77);        (* konstante Anzahl *)
    FOR i:=1 TO 10 DO
        MachVieleSterne(i);     (* Wert bestimmt eine Variable *)
END.