Einführung in die Programmiersprache Pascal Teil 4

Wie schon im letzten Teil angekündigt, geht es diesmal um Prozeduren (procedure) und Funktionen (function). Diese Elemente haben eine große Bedeutung für die Blockstruktur von Pascal.

Ein komplexes Programm, das aus einer unüberschaubaren Anzahl von Anweisungen besteht, kann in kleinere Abschnitte aufgeteilt werden. Die Abschnitte erledigen jeweils einen Teil des Problems und sind dabei leicht überschaubar. Außerdem können sie unter Umständen getrennt vom Haupt-programm erstellt und getestet werden. Danach werden sie in das Programm eingefügt bzw. das Programm wird um sie herum aufgebaut. Dieses Verfahren der 'schrittweisen Verfeinerung’ des Problems verringert entscheidend die Fehleranfälligkeit des Programms und erleichtert Fehlersuche und Analyse.

Prozeduren und Funktionen können, wenn sie einmal definiert sind von einem Programm beliebig oft aufgerufen werden. Dadurch werden manche Programme erheblich kürzer und übersichtlicher.

Einige Prozeduren und Funktionen sind standardmäßig schon in PASCAL definiert. So zum Beispiel:

PROZEDUREN: write, read
FUNKTIONEN: abs, sin, cos

Interessanter sind jedoch die vom Benutzer definierten Prozeduren und Funktionen, denen wir uns nun zuwenden wollen.

Prozeduren und Funktionen müssen im Vereinbarungsteil definiert werden. Dabei muß, wie schon im ersten Teil des Kurses erwähnt, eine festgelegte Reihenfolge beachtet werden:

VEREINBARUNGSTEIL

label

const
type
var

procedure
function

PROZEDUREN

Die Definition einer Prozedur hat folgende Form:

prozedure Name (Parameter);
Vereinbarungen;
begin
    Anweisung(en)
end;

Die Aufzählung der Parameter entfällt, wenn die Prozedur keine benötigt. Wenn jedoch Parameter vorhanden sind, muß der jeweilige Datentyp angegeben werden. Dies geschieht wie bei der Variablendeklaration im Hauptprogramm.

Unter dem Punkt VEREINBARUNGEN werden, falls vorhanden, die lokalen Konstanten, Variablen usw. definiert. Hier können dann auch wieder Prozeduren und Funktionen deklariert werden, wodurch sich ineinander verschachtelte Blöcke (siehe unten) ergeben.

Die Anweisungen der Prozedur werden von BEGIN und END umschlossen, wobei hinter END ein Semikolon steht.

Die nun folgenden Programme zeigen die Anwendung von Prozeduren:

Listing 1 zeigt eine Prozedur (ZEIGER) ohne Parameter. Sie beinhaltet nur eine Reihe von WRITELN-Anweisungen und führt diese beim Aufruf durch das Hauptprogramm aus. Der Aufruf besteht hierbei nur aus dem Wort ZEIGER.

Struktogramm 1

program DEMO_Procedure;

var anzahl :    integer;

procedure ZEIGER;
    begin
        writeln ('     *    ');
        writeln ('    ***   ');
        writeln ('   *****  ');
        writeln ('  ******* ');
        writeln (' *********');
        writeln ('    ***   ');
        writeln ('    ***   ');
        writeln ('    ***   ');
        writeln ('    ***   ');
        writeln ('    ***   ');
        writeln;writeln 
    end; { von ZEIGER }

begin { Hauptprogramm }

for anzahl:=1 to 10 do 
    ZEIGER

end. { Hauptprogramm }

Listing 1

Auch das Programm TASCHENRECHNER (Listing 2) enthält einfache Prozeduraufrufe ohne Parameterübergabe. Man kann jedoch den Vorteil der Zerlegung eines Programmes in Module (bzw. Teile) sehr gut erkennen, denn das Hauptprogramm besteht nur noch aus den Anweisungen:

    ANLEITUNG;  
    EINGABE;  
    RECHNUNG;
    AUSGABE

Die Technik der Modularisierung ist hier sehr weit betrieben worden. Der Grundgedanke dieser Technik wird damit besonders hervorgehoben. Das Programm ist so sehr übersichtlich geworden und außerdem läßt sich jede Prozedur schnell verändern oder korrigieren.

Struktogramm 2

program TASCHENRECHNER;

var operand1,operand2,ergebnis : real; 
    operator    :   char;

procedure ANLEITUNG; 
    begin
        writeln ('als Gperatoren sind nur und / erlaubt’);
    end; { von ANLEITUNG }

procedure EINGABE; 
    begin
        write ('Operandi : '); readln (operandi); 
        while (operator<>'+') and (operator<>'-') and 
            (operator<>'*') and (operator<>'/') do 
            begin
                write ('operator : '); readln (operator) 
            end;
        write ('Operand2 : '); readln (operand2) 
    end; { von EINGABE }

procedure RECHNUNG; 
    begin
        case operator of
            '+': ergebnis:=operand1+operand2;
            '-': ergebnis:=operand1-operand2;
            '*': ergebnis:=operand1*operand2;
            '/': ergebnis:=operand1/operand2;
        end
    end; { von RECHNUNG )

procedure AUSGABE; 
    begin
        writeln('Ergebnis :',ergebnis) 
    end;

begin { Hauptprogramm }

ANLEITUNG;
EINGABE;
RECHNUNG;
AUSGABE

end. { Hauptprogramm }

Listing 2

Das Programm CURSORPOSITIONIERUNG (Listing 3) zeigt die Übergabe von Parametern an eine Prozedur. Bei der Prozedurvereinbarung werden die Variablen 'horizontal’ und 'vertikal’ als Integer definiert. Das Hauptprogramm muß nun beim Aufrufen der Prozedur zwei Variablen des gleichen Datentyps übergeben. Der entsprechende Aufruf lautet:

    CURSOR(X,Y)

Da die Variablen x und y auch vom Datentyp Integer sind, gibt es keine Fehlermeldung. Die unterschiedliche Benennung der Variablen in der Prozedur (horizontal, vertikal) und im Hauptprogramm (x,y) ist möglich, weil nicht die Variable, sondern nur ihr Wert übergeben wird. Dies ist, wie man später sehen wird, von großer Bedeutung für die Handhabung von Prozeduren.

Innerhalb der Prozedur werden außerdem zwei weitere Variablen (h,v) deklariert. Sie sind lokale Variablen und als solche nur innerhalb dieser Prozedur definiert (siehe Lokale Vereinbarungen).

Anmerkung: Wie man bei diesem Programm erkennen kann, werden Variablen, die in einer Prozedur (oder Funktion) definiert sind, nicht bei der Variablendeklaration im Hauptprogramm angegeben.

FUNKTIONEN

Die Vereinbarung einer Funktion sieht folgendermaßen aus:

function name(Parameter);typ;
    Vereinbarungen;
begin
    Anweisung(en);
end;

Funktionen können als eine spezielle Form der Prozeduren angesehen werden. Sie liefern jedoch im Gegensatz zu diesen einen Funktionswert.

Die Vereinbarung einer Funktion sieht deshalb genauso wie die der Prozedur aus, doch muß hier zusätzlich der Datentyp des Funktionswerts angegeben werden.

Wie schon bei der Prozedur erläutert, können auch bei der Funktion lokale Konstante, Variablen usw. definiert werden.

Der Funktionswert wird innerhalb des Anweisungsteils festgelegt und dann an das Hauptprogramm übergeben.

Anhand der folgenden Beispiele wird der Funktionsaufruf verdeutlicht:

Das Programm TANGENS (Listing 4) definiert die Tangensfunktion, die sonst in Pascal nicht vorhanden ist. Dabei ist sowohl der Parameter (x) als auch der Funktionswert vom Typ REAL. In Anweisungsteil der FUNCTION wird der Funktion ihr Wert zugewiesen:

tan: = sin(x)/cos(x)

Struktogramm 3

program CURSOROPSITIONIERUNG; 

var x,y : integer;

procedure Cursor(horizontal,vertikal :  integer);
    var h,v :   integer;
    begin
        for v:=1 to vertikal do 
            writeln; 
        for h:=1 to horizontal do 
            write ('    ');
    end; 

    begin

    write ('Cursorposition: x y ------> ');
    read (x,y);
    Cursor(x,y); 
    write ('hier !')

end.

Listing 3

Vom Hauptprogramm wird die Funktion nun wie die schon vordefinierten Funktionen (sin, cos usw.) aufgerufen:

    tan(x)

Der Parameter des Funktionsaufrufs und der Parameter der Funktion haben die gleiche Bezeichnung (x). Dies ist bei diesem Beispiel zwar sinnvoll, um die Variable X besser verfolgen zu können, aber, wie auch bei einer Prozedur, nicht notwendig.

Ähnlich wie dieses Programm ist das nun folgende. In Listing 5 wird die Potenzfunktion beschrieben. Auch sie ist nicht als Standardfunktion in Pascal vorhanden, und so ist ihre Definition manchmal von Nutzen.

Der Funktionsaufruf übergibt diesmal zwei Parameter (x,y), die dann in der Funktion als EXPONENT und BASIS angesprochen werden.

Anmerkung: Ein Funktionsaufruf kann auch mehr als zwei Parameter an eine entsprechende Funktion übergeben.

Im nächsten Programm (Listing 6) sind zwei Funktionen definiert. Das Hauptprogramm ruft nacheinander die beiden Funktionen (GGT und KGV) auf. Innerhalb der Funktion KGV wird dann noch einmal die Funktion GGT aufgerufen.

Funktionen können sich also auch gegenseitig aufrufen. Dabei muß jedoch bei der Funktionsvereinbarung erst die aufgerufen und dann die aufrufende Funktion deklariert werden.

Struktogramm 4

program TANGENS; 

var x : real;

function TAN (x : real) : real; 
    begin
        tan:=sin(x)/cos(x) 
    end;

begin

    writeln ('TANGENS <x>'); 
    readln (x); 
    writeln (tan (x))

end.

Listing 4

LOKALE VEREINBARUNGEN

Wenn man sich mit Prozeduren und Funktionen, als spezielle Form der Prozedur, beschäftigt, ist es wichtig, sich mit dem Geltungsbereich von Variablen zu befassen.

Die im Vereinbarungsteil einer Prozedur deklarierten Variablen haben die (nützliche) Eigenschaft nur dort definiert zu sein. Sie sind also lokale Variablen.

Wenn man eine Prozedur als Block versteht, so gelten alle dort gemachten Deklarationen nur innerhalb dieses Blocks.

Da Blöcke ineinander verschachtelt werden können, gelten dementsprechend die Deklarationen auch in den inneren Blöcken, es sei denn sie werden dort anders deklariert (siehe folgendes Beispiel).

Dies hat den Vorteil, daß innerhalb von Prozeduren beliebige Variablen verwendet werden können, ohne auf den Rest des Programms Rücksicht nehmen zu müssen. Es kommt so nicht zu schwer auffindbaren Fehlern, die durch die mehrmalige Verwendung einer Variablen auftreten.

Struktogramm 5

program POTENZIEREN; 

var x,y :   integer;

function POT (exponent,basis : integer) : integer; 
    { y hoch x }

    begin
        pot:=round(exp(exponent*ln(basis))); 
    end; { von POT }

begin

    writeln ('POTENZIEREN y hoch x'); 
    readln (y,x); 
    writeln (pot(x,y))

end.

Listing 5

Struktogramm 6

program KGV;
        { Kleinstes Gemeinsames Vielfaches }

var zahll,zahl2 :   integer;

function GGT(zahl1,zahl2 : integer) : integer;
        { Groesster Gemeinsamer Teiler )
begin
    while zahll<>zahl2 do
        if zahl1 >zahl2 then zah11:=zahl1-zah12 
                        else zahl2:=zahl2-zahl1;
    ggt:=zahl1; 
end; { von GGT }

function KGV(zahl 1,zahl 2 : integer) : integer;
    begin
        kgv:=zahl1 div GGT(zah11,zah12)*zahl2 
    end;

begin { Hauptprogramm }

    write ('1. Zahl : '); readln (zahl1); 
    write ('2. Zahl : '); readln (zahl2); 
    writeln(' GGT : ',GGT(zah11,zah12):2); 
    writeln(' KGV : ',KGV(zah11,zah12):2)

end. { Hauptprogramm }

Listing 6

Das folgende Programm demonstriert den Wertebereich von lokalen Variablen:

program lokale_Variable;

var i : integer;

procedure schleife; 
    var i : integer; 
    begin
        for i:= 1 to 10 do 
            write (i)
    end;

begin (Hauptprogramm)
    for i: = 1 to 100 do
        schleife
end

Obwohl die Variable i im Hauptprogramm und in der aufgerufenen Prozedur vorkommt, beeinflußt dies das Programm nicht.

PROZEDUREN MIT EIN/AUSGABEPARAMETERN

Bisher wurden nur Prozeduren ohne Parameter oder mit Eingabeparametern betrachtet. Es gibt aber noch die Möglichkeit, Prozeduren mit Ein- und Ausgabeparametern zu deklarieren.

program demo1; 

var x : real;

procedure ADDITION(a: real); 
    begin 
        a:=a+1 
    end;

begin
    x: = 10;
    ADDITION(x);
    write(x)
end.

Beim Starten des Programms erhält man für x den Wert 10. Dies liegt daran, daß zwar der Wert von x (hier: 10) an die Prozedur übergeben und dort um Eins erhöht wird, aber dann nicht

mehr an die Variable x zurückübergeben wird. Um für x den gewünschten Wert zu erhalten, muß man deshalb den Eingabeparameter der Prozedur auch als Ausgabeparameter festlegen. Das Programm sieht dann wie folgt aus:

programm demo2;

var x : real;

procedure ADDITION(VAR a :real); 
    begin 
        a:=a+1 
    end;

begin
    x:= 10;
    ADDITION(x);
    write(x)

end.

Durch die Festlegung von ’a’ in der Parameterliste der Prozedur als Variable (VAR) kann ihr Wert wieder an das Elauptprogramm übergeben werden. Die Variable hat deshalb nach Beendigung des Programms den Wert 11.

Als abschließendes Beispiel zu den Prozeduren folgt nun das Programm BRUCHADDITION (Listing 7). Es wird hier wieder die FUNCTION GGT eingesetzt und zusätzlich die PROCEDURE KUERZEN. Die Funktion wird von der Procedur aufgerufen und steht deshalb im Vereinbarungsteil vor dieser.

In diesem Programm wird noch einmal die Parameterübergabe zwischen Hauptprogramm, Prozeduren und Funktionen verdeutlicht.

Anmerkung: Bei diesem Programm sind z, n und g lokale Variablen der Prozedur KUERZEN. Ihr Wert ist deshalb nur innerhalb dieser Prozedur abfragbar, außerhalb führt eine Abfrage zu einer Fehlermeldung. Die Variablen ZAEHLER1, ZAEHLER2 usw. sind dagegen globale Variablen. Sie gelten auch im Hauptprogramm und sind in der Prozedur und in der Funktion abfragbar.

Im nächsten Teil folgt die Besprechung von Datentypen und Feldern.

(MN)

Struktogramm 7

program BRUCHADDITION;
    { Berechnung der Summe in gekuerzter Form }

var zaehler1,zaehler2,zaehler,
    nenner1,nenner2,nenner :    integer;

function GGT(x,y :  integer) : integer;
    begin
        while x<>y do
            if x>y then x :=x-y 
                    else y:=y-x;
            ggt:=x 
        end; { von GGT }

procedure KUERZEN(var z,n : integer); 
    var g : integer;
    begin
        g:=ggt(z,n); 
        z:=z div g; 
        n:=n div g 
    end;    { von KUERZEN }

begin   {   Hauptprogramm   }
    writeln ('BRUCHADDITION'); 
    write ('1. Bruch : '); 
    readln (zaeh1er1,nenner1); 
    write ('2. Bruch : '); 
    readln (zaehler2,nenner2); 
    writeln;write1n;
    zaehler:=zaehler1*nenner2+zaehler2*nenner1; 
    nenner :=nenner1*nenner2;
    KUERZEN(zaehler,nenner);
    writeln (zaehler1:4,zaehler2:7,zaehler:9);
    writeln ('---- + ---- = ------');
    writeln (nenner1 :4,nenner2 :7,nenner :9)

end.    {   Hauptprogramm   }

Listing 7



Links

Copyright-Bestimmungen: siehe Über diese Seite
Classic Computer Magazines
[ Join Now | Ring Hub | Random | << Prev | Next >> ]