Prozeduren sind wie Programme aufgebaut, d.h. sie haben einen Namen, einen Deklarationsteil, in dem Variablen (und Prozeduren) vereinbart werden und einen Ausführungsteil, den Prozedurrumpf. Man kann Teile des Programmtextes in Prozeduren schreiben (verkapseln), um das Programm zu strukturieren und Wiederholungen zu vermeiden. Der größte Vorzug dieses Konzeptes aber ist die Möglichkeit, dass sich Prozeduren selbst aufrufen, d.h. die rekursive Programmierung.
Will man Prozeduren verwenden, so muß man sie vereinbaren, d.h. ihren Text angeben. Dies geschieht wie jede Vereinbarung im Deklarationsteil. Im Ausführungsteil kann man diese Prozeduren dann verwenden, d.h. aufrufen.
Seien A,B,C Anweisungen
program Test;
procedure
P1
begin
A; P2; P2 end;
procedure
P1
begin
B; P3; P3 end;
procedure
P3
begin
C end;
begin
P1
end.
Die Reihenfolge der durchgeführten Anweisungen ist ABCCBCC
Der Effekt eines Aufrufs einer parameterlosen Prozedur ist derselbe, also wenn man den Prozedurtext an die Stelle des Aufrufs kopierte.
Im Prozedurkopf hinter dem Namen der Prozedur kann eine Liste von Namen aufgeführt werden, die man die formalen Parameter der Prozedur nennt. Beim Aufruf muß dann hinter dem Namen der Prozedur ebenfalls eine Liste der Variablennamen stehen, die an die Prozedur übergeben werden sollen, auf die die Prozedur angewandt werden soll. Diese Namen nennt man die aktuellen Parameter. Diese Übergabe der aktuellen Parameter an die formalen Parameter kann auf dreierlei Weise geschehen:
Die Namen der formalen Parameter einer Prozedur können mit den Namen der Variablen des Hauptprogramm kollidieren. Dann gilt: innerhalb der Prozedur gelten die Namen der Parameterliste. Die Namen der außenstehenden Variablen gelten als überschrieben, sie haben innerhalb der Prozedur keine Bedeutung.
program Test;
var
y: integer;
procedure
P1(x: integer);
begin
x:=2 end;
procedure
P2(var x: integer);
begin
x:=2 end;
procedure
P3(const x: integer);
begin
x:=2 end;
begin
y:=3;
P1(y);
P2(y);
P3(y);
end.
Bei Aufruf der Prozedur P1 (call by value) wird für den formalen Parameter (Werteparameter) ein eigenes Speicherfeld von Typ integer unter dem temporären Namen x angelegt und der Wert der Variablen y dort hineinkopiert. Dann wird die Prozedur auf dieses Feld ausgeführt (d.h. 2 hineingeschrieben). Am Ende der Ausführung werden alle temporär angelegten Felder und alle lokalen Variablen der Prozedur wieder gelöscht. Das bedeutet: nach Ausführung der Prozedur P1 ist nichts geschehen. Eine Prozedur, die nur Werteparameter hat, wird also außerhalb nie etwas verändern.
Bei Aufruf der Prozedur P2 (call by reference) sind die formalen Parameter (Variablenparameter) neue Namen für die Felder die durch die aktuellen Parameter benannt werden. Innerhalb der Prozedur sind diese neuen Namen gültig, die alten Namen sind temporär überschrieben von den neuen Namen. Bei Ausführung von P2 wird also das Feld y neu durch x benannt und die Zahl 2 hineingeschrieben. Am Ende der Ausführung werden die neuen Namen gelöscht und die alten Namen wieder gültig. Der Boolesche Ausdruck "y = 2" ist dann also wahr. Eine Prozedur, die außerhalb ihrer Laufzeit eine Veränderung hinterlassen soll, muß also wenigstens einen Variablenparameter haben. Ein weiterer Vorzug ist, dass (außer für den neuen Namen) kein neuer Speicherplatz gebraucht wird, was bei großen Feldern erheblich Speicher und Zeit sparen kann. Ein Nachteil ist, dass die durch die aktuellen Parameter benannten Felder nicht vor Veränderung geschützt sind, die Prozedur also ungewollte Seiteneffekte haben kann.
Bei Aufruf der Prozedur P3 (call by reference) sind die formalen Parameter (Konstantenparameter) wie die Variablenparameter neue Namen, mit dem Unterschied, dass die von ihnen benannten Felder nicht verändert werden können. Diese Art bietet sich also nur an, wenn man eigentlich call by value machen möchte, aber das Feld des aktuellen Parameters sehr groß ist.
program Test;
var
a,b,c: integer;
procedure
ADD1(var a,b,c:integer;
begin
c:=a+b;
c:=c+a
end;
procedure
ADD2(a,b:integer, var c:integer);
begin
c:=a+b;
c:=c+a
end;
begin
a:=1;
b:=2; c:=3;
ADD1(c,a,c);
ADD2(c,a,c);
end.
Zuerst werden die von a, b, c benannten Integerfelder mit 1, 2 und 3 belegt.
Der Aufruf von ADD1 kreiert 3 neue Namen: a,b,c. Diese Namen gab es schon vorher, die gelten aber als überschrieben Der Name a steht jetzt für das Feld, das vorher mit c benannt wurde, der Name b für das vorher mit a benannte Feld und der Name c steht wieder für das Feld, das vorher auch schon mit c benannt wurde. Die Namen a und c benennen also dasselbe Feld.
In c steht eine 3. Die erste Anweisung schreibt a+b = 3+1 = 4 in Feld c. Die zweite Anweisung schreibt c+a = c+c = 4+4 = 8 in das Feld c . Danach werden die neuen Namen wieder gelöscht und die alten Namen haben wieder ihre Bedeutung. In a steht jetzt immer noch 1, in b eine 2 und in c jetzt das Ergebnis der Prozedur: eine 8.
Der Aufruf von ADD2 kreiert 2 neue temporäre Felder , die durch die "neuen" Namen a und b benannt werden, während der neue Namen c auch der alte Namen c ist und das entsprechende Feld benennt. Mit a und b meint man jetzt innerhalb der Prozedur also die neuen Felder, in die die Inhalte der von den vormals von c und a benannten Felder kopiert werden. D.h. in a kommt der Inhalt von vormals c also 8 und in b kommt der Inhalt von vormals a also 1. c steht für das alte Feld c und enthält ebenfalls 8.
Die erste Anweisung schreibt a+b = 8+1 = 9 in das Feld c. Die zweite Anweisung schreibt c+a = 9+8 = 17 in Feld c. Danach werden die temporären Felder und Namen gelöscht und die alten Namen gelten wieder. In a steht jetzt 1, in b eine 2 und in c steht 17.
Variablen in Prozeduren
Die in einer Prozedur vorkommenden Variablen können in drei Typen eingeteilt werden.
Lokale Variablen: Wie in jedem Programm können auch in einer Prozedur Variablen deklariert werden. Es wird ein Name und ein Typ vereinbart. Existiert der Name schon außerhalb der Prozedur, so gilt der alte Name als (vorübergehend) überschrieben oder besser verdeckt. Innerhalb der Prozedur gilt der neue Name, allerdings nur solange die Prozedur läuft. Am Ende der Prozedur wird Name und zugehöriger Speicherplatz gelöscht. Dann wird der alte Name wieder gültig (sichtbar). Solche Variablen nennt man lokal, weil sie nur innerhalb und zur Laufzeit der Prozedur existieren.
Formale Parameter: Ein Parameter kann wie eine lokale Variable betrachtet werden, soweit es sich um einen Werteparameter handelt. Ein Variablen- oder Konstantenparameter, ist nur ein (neuer) Name, der einen schon früher angelegten Speicherplatz benennt. Aber auch für ihn gilt, dass sein Name nur lokal und für die Laufzeit der Prozedur gültig (sichtbar ) ist.
Globale Variablen: Eine globale Variable ist eine Variable, die außerhalb der Prozedur deklariert worden ist. Sie kann innerhalb der Prozedur benützt werden, soweit ihr Name nicht schon durch einen formalen Parameter oder eine lokale Variable verdeckt worden ist. So kann eine Prozedur auch ohne (Variablen-) Parameter nach außen wirken. Solche Außenwirkungen, die nicht über Variablenparameter laufen, nennt man auch Seiteneffekte. Sie gelten als unelegant, weil sie nicht durch die Parameterliste dokumentiert und nachvollziehbar sind. Sie werden aber genützt, wenn die Prozedur geschrieben wurde, um das Programm zu strukturieren, und nicht außerhalb des Programms verwandt wird. Die Parameterliste einer Prozedur nennt man auch seine Schnittstelle, weil sie (normalerweise) die Verbindung nach außen darstellt. (Man stellt sich vor, dass die Prozedur an dieser Stelle aus seinem Kontext herausgeschnitten ist).