Home Computer Pascal Kurs Site Map counter

Jetzt lerne ich Pascal... Teil 2

Programmstrukturen

In diesem Teil geht es nun um die grundlegenden Programmstrukturen, die jede Programmiersprache aufweist: Schleifen um Programmteile zu wiederholen und Abfragen um abhängig von bestimmten Bedingungen Befehle ausführt. Wie im letzten Kurs ist gültiger Pascal Code in blau und Schlüsselworte im Text in roter Farbe. Schlüsselworte habe ich groß geschrieben. Sie wissen aber nach dem ersten Teil, das Groß-Kleinschreibung bei Pascal egal ist. anders als bei c wo "a" und "A" zweierlei Dinge sind!

Schleifen

Ohne Schleifen kommt keine Programmiersprache aus. Eine Schleife ist eine Möglichkeit Anweisungen zu wiederholen. In allen modernen Programmiersprachen gibt es drei Schleifentypen die folgende Eigenschaften aufweisen:

Diese Schleifen finden sie auch in anderen Programmiersprachen wie C,C++ und Java.

Die FOR Schleife

Die FOR Schleife hat in Pascal große Ähnlichkeit zu ihrem Pendant in BASIC und ist nicht so leistungsfähig wie FOR in C oder Java. Dafür ist die Syntax relativ leicht zu erlernen

Die Syntax der FOR Schleife ist:

FOR Laufvariable:=Ausdruck1 TO Ausdruck1 DO Anweisung;


FOR, TO und DO sind Schlüsselwörter.

Ausdruck1 und Ausdruck2 sind Ausdrücke, welche die Start- und Endbedingung angeben. Ausdruck1 wird der Laufvariablen beim Start zugewiesen. Die Schleife wird solange ausgeführt bis Ausdruck2 erreicht wird. Beides müssen ganzzahlige Werte sein, die man dem Variablentyp der Laufvariablen zuweisen kann, also keine Wahrheitswerte, sondern abhängig von der Variable eine Zahl oder ein Buchstabe.

Laufvariable ist eine Variable die während der Schleife verändert wird. Sie kann hoch gezählt werden oder erniedrigt werden. Wird sie hoch gezählt so wird das Schlüsselwort TO benutzt. Beim Herunterzählen das Schlüsselwort DOWNTO. Es gibt für die Laufvariablen einige Einschränkungen:

Es kann nur ein Typ sein der durch Ganzzahlen dargestellt wird. Von den Typen die Sie bisher schon kennen sind dies Char, Byte, Word, Shortint, Integer und Longint.

Die Variable wird nur immer um 1 erhöht oder erniedrigt. Das folgende Programm würde z.B. alle Zahlen von 1 bis 10 ausgeben:

Soll dagegen heruntergezählt werden, so würde man schreiben:

VAR i: integer;
BEGIN
  FOR i:=1 to 10 DO
    writeln(i);
END.


Beachten Sie, das dabei auch Start und Endwert vertauscht sind!

Soll mehr als eine Anweisung ausgeführt werden, so setzt man diese in einen BEGIN END Block - Jetzt wird Ihnen sicher auch klar warum man diese braucht.

Es gibt zur FOR Schleife noch ein paar Dinge die wichtig sind:

Der Endwert wird bestimmt, wenn die Schleife ein erstes mal ausgeführt wird, danach nicht mehr. Als Beispiel:

VAR i,k: integer;
BEGIN
  k:=2;
  FOR i:=1 to k DO
  BEGIN
    writeln(i);
    k:=5;
  END;
END.

Wird nicht die Zahlen 1 bis 5 sondern nur 1 und 2 ausgeben, da der Wert von k der in der Schleife geändert wurde nicht mehr für die Berechnung des Ausdrucks verwendet wird. D.H. bei der FOR Schleife werden Start und Endausdruck vor der Ausführung berechnet, danach nicht mehr !

Man kann die Schleifenvariable manipulieren. Nichts hindert Sie in den Block ein

i:=i+1;

einzufügen. Das ganze hat nur ein Problem. Mal abgesehen davon das es ein ganz dreckiger Programmierstil ist, ist das Ergebnis undefiniert und vom Compiler abhängig was herauskommt. Das kann sein, das I nun in 2 er Schritten erhöht wird, es kann aber auch ein Laufzeitfehler sein, oder das Programm wird nicht übersetzt. Brauchen sie eine Variable die ihren Wert in anderen Schritten ändert so ist es geschickter die WHILE Schleife zu verwenden oder eine Variable aus der Laufzeitvariable abzuleiten. (Schritt mit I machen und Einführung von J mit der Zuweisung j:=2*i;). Der Wert der Schleifenvariablen ist nach der Ausführung undefiniert. Das ist so in der Sprachdefinition vorgesehen und hat den Nutzen, das man ein CPU Register nutzen kann, dieses kann aber durch die nächsten Befehle überschrieben werden.

Die FOR Schleife werden Sie immer benutzen, wenn es darum geht, das Sie zur Laufzeit wissen, wie oft eine Schleife ausgeführt werden muss. Das folgende Beispiel z.B. ist eine Zinsenberechnung, bei dem die Zinsen in monatlichen Raten eingezahlt wird. Sie sehen dort auch noch eine zweite Schleife: Die REPEAT UNTIL Schleife.

PROGRAM Zinsenberechnung;

VAR Startkapital,Einzahlung,Kapital,Zinssatz: Double;
     Monate,Zaehler                         : Integer;
     Wahl                                   : Char;

BEGIN
     REPEAT
         Write('Wie hoch ist das Startkapital (in DM)? ');
         ReadLn(Startkapital);
         Write('Wie hoch ist die monatliche Einzahlung? ');
         ReadLn(Einzahlung);
         Write('Wie lange wollen Sie sparen (in Jahren)? ');
         ReadLn(Monate);
         Write('Wie hoch ist der Zinssatz (in Prozent)? ');
         ReadLn(Zinssatz);
         Monate:=Monate*12; {Umrechnung Jahre in Monate}
         Zinssatz:=1+(Zinssatz/100/12); {Umrechnung in Prozent/Monate}
         Kapital:=Startkapital;
         FOR Zaehler:=1 TO Monate DO Kapital:=(Kapital*Zinssatz)+Einzahlung;
         WriteLn('Sie haben insgesamt eingezahlt: ',Startkapital+Monate*Einzahlung:10:2);
         WriteLn('...und bekommen mit Zinsen: ',Kapital:10:2);
         WriteLn;
         Write('Nochmal (J/N)');
         ReadLn(Wahl);
     UNTIL (Wahl='N') OR (Wahl='n');
END.

Die WHILE Schleife

Anders als die FOR Schleife wird bei der WHILE Schleife eine logische Bedingung als Abbruchbedingung für die Schleife benutzt. Damit kann man beliebige Ausdrücke auswerten. die Syntax der WHILE Schleife ist:
WHILE Bedingung DO Anweisung;

Die Bedingung kann ein beliebiger Ausdruck sein. Wenn er komplex wird ist es eine gute Idee ihn in Klammern () zu setzen. Solange dieser Ausdruck erfüllt ist, wird die Schleife ausgeführt und die Anweisung (bzw. Block) ausgeführt. Der typische Einsatz der WHILE Schleife ist das Einlesen von Dateien. Dann findet man oft solche Schleifen:

WHILE NOT(Eof(Datei)) DO Readln(Datei,Zeile);

EOF ist eine Statusvariable die eine geöffnete Datei zurückgibt. EOF wird wahr (True) wenn das Dateiende erreicht wird und hat sonst den Wert falsch. (False) Das Ergebnis ist also ein Wert des Typs Boolean. Da die Schleife aber nur durchgeführt wird, wenn EOF den wahren Wert (True) hat, muss True in False umgewandelt werden. Das macht die Funktion NOT, die jeweils einen Wahrheitswert in sein Gegenteil umkehrt. Alternativ hätte man auch schreiben können:

WHILE Eof(Datei)=False DO Readln(Datei,Zeile);

Das wichtigste bei der WHILE Schleife ist, das die Bedingung bei jedem Schleifendurchlauf geprüft wird, und zwar bevor die Nutzanweisung bzw. Block ausgeführt wird. Das obige Beispiel funktioniert so auch, wenn die Datei leer ist, d.h. nach dem Öffnen schon True von EOF zurückgegeben wird.

Die REPEAT UNTIL Schleife

Wenn Sie die WHILE Schleife verstanden haben, so wird Ihnen die REPEAT Schleife keine Probleme bereiten. Die Syntax von REPEAT ist:
REPEAT
  Anweisungen;
  Anweisungen;
UNTIL Bedingung;

Da REPEAT selbst einen Block beinhaltet, braucht man hier ausnahmsweise kein BEGIN..END;

Die REPEAT Schleife wertet die Bedingung erst bei UNTIL aus, d.h. die Schleife wird mindestens einmal durchlaufen. Während man bei WHILE die Schleife durchführt solange die Bedingung True ist (Umgangssprachlich: Wiederhole solange... erfüllt ist), wird bei REPEAT die Schleife beendet wenn die Bedienung erfüllt ist (Umgangssprachlich: Wiederhole solange bis... erfüllt ist). D.h. die Schleife wird durchgeführt, solange die Bedingung den Wahrheitswert Falsch (False) ergibt.

Der Typische Einsatzzweck von REPEAT Schleifen sind Eingaben über Tastatur. Im obigen Beispiel wird die Zinsberechnung solange wiederholt, bis der Anwender "N" eingibt, bei der Frage nach einem erneuten Durchlauf.

Logische Ausdrücke

Da man Logische Ausdrücke bei Schleifen braucht, hier eine kleine Einführung. Jeder Vergleich ergibt einen Wahrheitswert zurück der entweder True oder False sein kann. Vergleiche sind:

Ist-Gleich: z.B.: Einkommen=3000
Kleiner als: z.B.: Einkommen<3000
Größer als: z.B.: Einkommen>3000
Größer gleich: z.B.: Einkommen>=3000
Kleiner gleich: z.B.: Einkommen<=3000
Ungleich: z.B.: Einkommen<>3000

Alle diese Ausdrücke liefern einen Wahrheitswert zurück. Dabei sind die Symbole <,> und = Operatoren. Logische Operatoren verknüpfen nun mehrere Wahrheitswerte zu einem neuen:

(Ausdruck1 AND Ausdruck 2)

AND als Schlüsselwort liefert nur Wahr zurück, wenn beide Wahrheitswerte wahr sind z.B.:

(Einkommen>3000) AND (Einkommen<4000)

liefert nur wahr zurück wenn ihr Einkommen größer als 3000 DM aber kleiner als 4000 DM ist. Die Klammern um die Ausdrücke sollten sie sich angewöhnen - sie machen es nicht nur sicherer, sondern die logischen Operatoren haben keine besonders hohe Priorität bei der Bearbeitung, so das sie sonst einen Fehler gemeldet bekommen können (Der Ausdruck muss ein Wahrheitswert ergeben, ohne die Klammern würde der Compiler zuerst versuchen die Verknüpfung zu machen und dann erst den Wahrheitswert der Einzelausdrücke zu bestimmen.

(Ausdruck1 OR Ausdruck 2)

Liefert nur Wahr zurück wenn einer oder beide der beiden Wahrheitswerte wahr ist z.B.:

(Einkommen>3000) OR (Einkommen<1000)

liefert wahr zurück wenn ihr Einkommen größer als 3000 DM oder kleiner als 1000 DM ist. (Einkommen>3000 OR Einkommen<4000) würde bei jedem Einkommen Wahr zurückliefern, denn es gilt sowohl für Einkommen über 3000 DM, wie auch für Einkommen unter 4000 DM.

(Ausdruck1 XOR Ausdruck 2)

Liefert nur Wahr zurück wenn genau einer der beiden Wahrheitswerte wahr ist z.B.:

(Einkommen>3000) XOR (Einkommen<=4000)

liefert wahr zurück wenn ihr Einkommen größer als 4000 DM oder kleiner als 3000 DM ist. In dem Bereich von 3000 bis 4000 DM werden beide Ausdrücke wahr, dann liefert XOR ein Falsch zurück. Xor gibt es bei Pascal als logischen Operator, nicht jedoch in vielen anderen Sprachen wie C,C++ und Java. XOR ist eine Operation die man daher selten bei Vergleichen findet, aber oft um Bits umzudrehen, dann kehrt XOR jeweils die Bits in ihr Gegenteil um, ein zweites XOR mit demselben Wert liefert den gleichen Wert zurück.

Bsp.:

$AA XOR $FF $55
$55 XOR $FF $AA

Binär:

10101010 = $AA
11111111 = $FF
-------------------
01010101 = $55

Es wurden durch die "Maske $FF" die Bits jeweils invertiert. Man sollte sich immer vergegenwärtigen, das hier zwei verschiedene Operatoren (eine Vergleichsoperation und eine Bitweise Verknüpfung) dasselbe Schlüsselwort benutzen. Man findet dies auch bei den anderen Operatoren: AND ergibt bei einem Bit 1 wenn beide Bits gesetzt sind (oft benutzt um Bits zu löschen). OR wenn eines gesetzt ist (Benutzt um Bits zu setzen) und NOT (invertiert jedes Bit).

NOT Ausdruck

Wandelt einen logischen wahr in einen logischen Falschwert um.

Schleifen Verlassen

Was macht man wenn man eine Schleife vorzeitig verlassen will? Beispielsweise kann ein Fehler bei der Verarbeitung des Codes eintreten oder man weiß bei dem Beginn der Schleife noch nicht die Abbruchbedingung und programmiert eine Endlosschleife die man irgendwie verlassen muss. In den neueren Pascal Dialekten (nicht aber bei TP 5.5) stehen dafür zwei Befehle zur Verfügung:

Break

Bricht eine FOR, WHILE oder REPEAT Schleife ab, und setzt die Ausführung dahinter fort. Break ist daher ein geschickter Befehl wenn man erkennt das eine weitere Abarbeitung der Schleife nicht nötig ist, z.B. eine Datei keinen gültigen inhalt hat (Sie erwarten Text und es ist eine Grafikdatei).

Continue

Oft hat man den Fall das man in einer Schleife mehrere Dinge tun muss und bestimmte Anweisungen nicht immer nötig sind. Mit continue kann man dann den Rest eines Blockes überspringen und die Schleife wird fortgesetzt. Das gleiche kann man oft auch erreichen wenn man die Sonderfälle in IF... THEN... ELSE setzt, doch das ist nicht so übersichtlich. Goto label

Goto soll hier nur der Vollständigkeit halber erwähnt werden. GOTO ist das typische Sprachelement von Basic und macht Programme unübersichtlich. Sie sollten es vermeiden, zumal man mit Exit, Break und Continue schon sehr gute Sprünge machen kann. Jedes Goto ist auch durch ein IF ersetzbar und moderne Sprachen wie Java kennen gar kein Goto mehr. Um Goto verwenden zu müssen, müssen Sie vor dem Code bei den Variablen ein Label deklarieren:

Label meinlabel;

Wohin dann gesprungen werden muss, setzten Sie das Label mit Doppelpunkt:

meinlabel:

Dorthin können Sie dann mit Goto springen:

goto meinlabel

Der Autor hat in den ersten Monaten nach dem Umstieg von Basic noch vereinzelt GOTO eingesetzt, in den letzten 16 Jahren jedoch in keinem Programm mehr! Es gibt noch zwei weitere Abbruchkommandos in Pascal, die nun auch schon unter Turbo Pascal 5.5 bekannt sind:

Exit;

beendet nicht nur eine Schleife sondern eine ganze Funktion bzw. Prozedur. Wir werden Exit noch besprechen, wenn es im Teil 3 um Funktionen und Prozeduren geht.

Halt(wert);

beendet das ganze Programm sofort und übergibt an das Betriebssystem den Wert, den sie z.B. mit ERRORLEVEL unter DOS abfragen können

Bedingte Anweisungen: IF THEN ELSE

Es wurde schon angesprochen: Wenn man nicht einen ganzen Block abhängig von einer Bedingung machen möchte, sondern nur einzelne Anweisungen so kann man die Abfrage mit IF THEN und ELSE machen. Die Syntax ist:

IF Ausdruck THEN Anweisung1 ELSE Anweisung2;

Das ganze hat ein paar Fallstricke. Der wichtigste: Das Semikolon ist das Ende der ganzen Anweisung. Haben Sie also einen ELSE Teil, so steht nach der ersten Anweisung kein Semikolon. Der ELSE Teil kann kommen, muss aber nicht. Wie immer kann man anstatt einer Anweisung auch einen Block mit BEGIN END machen, dann aber auch auf das Semikolon achten.

Man kann IF THEN ELSE Schachteln, das ELSE gehört dann immer zum letzten IF. Da dies sehr unübersichtlich wird, rate ich dazu hier das IF THEN ELSE in Blöcke zu Klammern, dann können keine Fehler passieren.

Ein Beispiel:

IF Einkommen>1000 THEN
IF Einkommen<2000 THEN Writeln('Gehaltserhöhung fordern!')
ELSE Writeln('Super Gehalt!')
ELSE Writeln('Du armer Tropf!');

Hier gehört die Ausgabe "Super Gehalt" zu der zweiten IF Abfrage und "Du armer Tropf" zur ersten, d.h. die ELSE werden genau wie die IF's nacheinander zugemacht. Verständlicher sieht derselbe Code so aus:

IF Einkommen>1000 THEN
BEGIN
  IF Einkommen<2000 THEN Writeln('Gehaltserhöhung fordern!')
  ELSE Writeln('Super Gehalt!')
END
ELSE Writeln('Du armer Tropf!');


Es ist nun klar, welcher Block wozu gehört. Beachten Sie auch, das erst am Schluss der letzten Anweisung das Semikolon kommt, denn vorher ist die verschachtelte IF Anweisung nicht zu Ende, d.h. die zweite IF Anweisung ist die Nutzanweisung des ersten IF's. Noch etwas wichtiges: In jeder Programmiersprache gibt es Probleme mit der Operatorreihenfolge. das heißt, dass man klammern muss, obwohl man es gedanklich nicht tun muss. Bei C ist es sehr schlimm, hier hat z.B. der Operator * für das Dereferentieren eine sehr geringe Bedeutung, wird aber häufig gebraucht. Bei Pascal ist die einzige Ecke wo es hakt, bei den logischen Operatoren:

if Zeile>"Tofu" and Auswahl=5 then Ausgabe;

wird nicht laufen. Der Grund: Die logischen Operatoren and,or,xor kommen zuerst, zuerst sollte aber der Vergleich ablaufen. Das heißt, wann immer Sie nicht mit einem reinen Wahrheitswert (True,False) oder einer Funktion die Boolean zurückliefert, arbeiten müssen Sie bei AND, OR und NOT klammern:

if (Zeile>"Tofu") and (Auswahl=5) then Ausgabe;

Kurzschlussverfahren

Bei etwas größeren Programmen haben sie oft ein Problem am Hals, dass der Compiler logische Ausdrücke im Kurzschlussverfahren auswertet. Das heißt wenn man eine Zeile hat wie
IF (Einkommen>3000 OR Chefok) THEN

Chefok soll eine Funktion sein die Wahr oder Falsch zurückliefert. Hat nun das Gehalt einen Wert größer als 3000 so ist die erste Bedingung erfüllt, und da bei OR es reicht wenn ein wert wahr ist, wird der Compiler sagen "Dann kann ich mir das Auswerten der Funktion Chefok ja schenken". Das nennt man Kurzschlussverfahren und es ist im allgemeinen ganz nützlich, nicht jedoch wenn Sie davon ausgehen, das die Chefok Funktion auf jeden Fall aufgerufen wird und diese z.B. andere Werte einstellt. Für diesen Fall finden Sie unter Compiler Einstellungen einen Eintrag der z.B. heißt "Boolean Evalation" und denn man auf "short circut oder "complete" stellen kann.

Im allgemeinen ist Short Circut eine gute Einstellung, denn sonst könnte es unter Delphi 2 aufwärts bei folgender Zeile Einen Fehler geben:

VAR Zeile: String;
IF (Length(Zeile)>0) AND (Zeile[1]<>' ') THEN

Ist aus irgendeinem Grund der String Zeile leer (0 Zeichen, Länge = length() = 0), so wird diese Instruktion bei Kompletter Auswertung einen Laufzeitfehler erzeugen, da man versucht auf das Element 1 zuzugreifen, welches nicht existiert. Beim Kurzschlussverfahren ist nach Feststellen der Länge Schluss, es wird nicht versucht auf den String zuzugreifen. Das ganze kann man auch vermeiden indem man dieselbe Zeile so programmiert:

IF (Length(Zeile)>0) THEN
IF (Zeile[1]<>' ') THEN

Doch das sind dann zwei verschachtelte IF's die schon wieder schwerer zu lesen sind. Sie werden derartige Strukturen sehr oft finden und sollten sie auch verwenden. Man nennt dies Wächterfunktionen. Sie wachen darüber, das ihr Programm hier nicht versucht auf nicht vorhandene Elemente zuzugreifen. Dazu muss aber die Auswertung auf Kurzschlussverfahren stehen. (In Smalltalk oder Java gibt es zwei Operatoren für and und or, jeweils einen für Complete und shortcut).

Mehrfahauswahl: CASE

Verzweigte IF's haben den Nachteil rasch unübersichtlich zu werden. Nun gibt es aber für einen Fall eine übersichtliche Alternative: Wenn man nur in den IF's Werte einer Variable abfragt, z.B. beim Auswerten von Tastendrücken welche Funktion aufgerufen wurde. In diesem Fall benutzt man die CASE Anweisung mit folgender Syntax:

CASE Variable OF
wert1: Anweisung1;
wert2: Anweisung2;
....
ELSE Anweisung;
END

Variable ist eine Variable die als Ganzzahlwert dargestellt werden kann, also eine Char oder eine der Integer Typen. Die folgenden Instruktionen umfassen jeweils einen Wert einen Doppelpunkt und die Anweisung bzw. einen Block der dann ausgeführt wird, wenn die Variable diesen Wert hat.

wert1: Anweisung1;

steht also für

IF Variable=Wert1 THEN Anweisung;


Anders als bei C können mehrere Werte zusammengefasst werden z.B.:

CASE Zeichen OF
  'A..'Z': Writeln('Großbuchstaben');
  'a'..'z' : Writeln('Kleinbuchstaben');
  'ä','Ä','ü','Ü','Ö','ö' : Writeln('Umlaute');
  'ß' : Writeln('Scharfes S');
  ELSE writeln('Kein Buchstabe!');
END;

Man sieht hier alle drei Möglichkeiten: Einzelne Werte ('ß'), Wertaufzählung (Umlaute) und Wertbereiche (Jeder Buchstabe zwischen A und Z). Findet keine Deckung statt, so wird der ELSE Teil angesprungen. Ein ELSE Teil ist jedoch optional. Anders als bei C muss man nicht mit Break aus einer Bearbeitung springen, sobald die Variable mit einem CASE Wert übereinstimmt, die restlichen Fälle von CASE werden dann nicht mehr durchsucht. Wichtig ist dies wenn Sie aus versehen überlappende Wertebereiche haben. Nur VPASCAL wird dies monieren. CASE ist in Pascal erheblich mächtiger als Switch in C.

Häufig werden Sie CASE einsetzen um auf verschiedene Tastaturkommandos zu reagieren.

Ihre Übungen:

Schreiben Sie ein Programm das von 0 auf 20 in Zweierschritten zählt und diese Zahlen ausgibt. Machen Sie das mit allen 3 Schleifen: FOR, WHILE und REPEAT. Hier ein Beispiel wie das aussehen sollte.

Schreiben Sie ein Programm, dass für ein eingegebenes Zeichen ausgibt, ob es:

ist. Versuchen Sie auch hier dies einmal mit IF's und einmal mit CASE zu realisieren. Ein Beispiel wie das Aussieht. Danach sollten Sie wissen wo Sie welche Schleife einsetzen und wann IF's oder wann CASE angesagt ist.

Zum Thema Computer ist auch von mir ein Buch erschienen. "Computergeschichte(n)" beinhaltet, das was der Titel aussagt: einzelne Episoden aus der Frühzeit des PC. Es sind Episoden aus den Lebensläufen von Ed Roberts, Bill Gates, Steve Jobs, Stephen Wozniak, Gary Kildall, Adam Osborne, Jack Tramiel und Chuck Peddle und wie sie den PC schufen. Das Buch wird abgerundet durch eine kurze Erklärung der Computertechnik vor dem PC, sowie einer Zusammenfassung was danach geschah, als die Claims abgesteckt waren. Ich habe versucht ein Buch zu schreiben, dass sie dahingehend von anderen Büchern abhebt, dass es nicht nur Geschichte erzählt sondern auch erklärt warum bestimmte Produkte erfolgreich waren, also auf die Technik eingeht.

Mehr über das Buch auf dieser eigenen Seite.

Sitemap Kontakt Neues Bücher vom Autor Buchempfehlungen Top 99