Home » Tutorials » Object Pascal/RTL » Delphi-Crashkurs

Delphi-Crashkurs

Prozeduren und Funktionen

Wie schon während der Beschreibung der case-Anweisung gesagt wurde, sind Codeteile, welchen eine ähnliche oder gar gleiche Funktion besitzen und oft vorkommen, nicht gerne gesehen. Wieso dies so ist, wird nach Einführung der Prozeduren noch einmal besprochen. Jetzt wird erst einmal beschrieben, wie Prozeduren und Funktionen eigentlich funktionieren.

Prozeduren

Die Einführung in die Prozeduren hat für Sie den Vorteil, dass es wieder etwas zu programmieren gibt. Das haben Sie übrigens Michael „Luckie“ Puff zu verdanken, der mir mit diesem Beispiel aus der Klemme geholfen hat.
Um zu sehen, wie eine Prozedur funktioniert, bauen Sie sich jetzt erst einmal besagtes Beispiel zusammen. Dazu legen Sie ein neues Projekt an und platzieren zwei Labels auf der Form. Der Ort ist eigentlich egal, am besten aber nebeneinander. Schließlich muss noch ein Button platziert und mit „Tauschen“ beschriftet werden.

Führen Sie einen Doppelklick auf die Schaltfläche aus, um den Quelltext so einzufügen, dass es hinterher so aussieht wie hier:

procedure TForm1.Button1Click(Sender: TObject);
var s1, s2 : String;
begin
  s1 := Label1.Caption;
  s2 := Label2.Caption;

  tauschen(s1,s2);

  Label1.Caption := s1;
  Label2.Caption := s2;
end;

Dabei fällt Ihnen sicher der Befehl „tauschen(s1, s2)“ auf. Das ist die Prozedur, die es noch zu schreiben gilt. Sie sieht folgendermaßen aus:

procedure tauschen(var s1, s2 : String);
var temp : String;
begin
  temp := s1;
  s1 := s2;
  s2 := temp;
end;

Diese fügen Sie über den Zeile mit „procedure TForm1….“ ein. Starten Sie nun das Programm und betätigen Sie den Button. Achten Sie dabei darauf, was mit der Beschriftung der Labels passiert! Wie Sie sehen, werden die Beschriftungen vertauscht.
Und nun nehmen Sie eine Änderung am Kopf der Prozedur „tauschen“ vor. Entfernen Sie das „var“ vor „s1, s2 …“. Starten Sie das Projekt erneut und klicken Sie erneut. Sie sehen, was passiert: nichts. Und anhand dieses „Phänomens“ wird im Folgenden erklärt, wie eine Prozedur arbeitet.
Dazu werde ich zuerst die Variante beschreiben, die nicht funktioniert. Die ist einfacher. Sie ahnen sicher schon, was eine Prozedur macht: sie fasst Befehle unter einem Namen zusammen. Wenn Sie die Prozedur „tauschen“ aufrufen, dann werden die Befehle ausgeführt, die Sie dort festgelegt haben. Die Prozedur ist im Grunde genommen ein kleines Programm für sich.
Aber ein solches Programm wäre sinnlos, wenn es ohne Kontakt zum Rest immer dieselben Befehle ausführen würde. Daher hat man es so eingerichtet, dass man einer Prozedur so genannte Parameter mitgeben kann.
Parameter, das sind die Dinger, die hinter dem Namen der Prozedur in Klammern stehen. Grob gesagt sind es Variablen, welche man beim Starten der Prozedur mit einem bestimmten Wert belegen kann. Dieser Wert ist dann in der Prozedur bekannt und man kann in der Prozedur mit dem Wert arbeiten. Ein Parameter ändert also das Ergebnis und die Aktionen einer Prozedur: anderer Wert, andere Aktion.
Was passiert nun in der Prozedur mit den Parametern s1 und s2? Sie werden getauscht. Ein solcher Tausch wird Ihnen während Ihrer Programmierertätigkeit sehr oft begegnen. Um den Wert zweier Variablen zu tauschen, braucht man immer eine Dritte. Anstatt dass ich dies nun mit vielen Worten beschreiben, sollten Sie sich einfach die Grafik ansehen.

Somit ist nun klar, was beim Aufruf von „tausche(s1, s2)“ passiert. Und da Sie vorher den Inhalt von Label1 in die Variable „s1“ geschrieben haben und den Inhalt von Label2 in die Variable „s2“, und nach dem Aufruf von „tausche“ das Ganze umgekehrt machen, sollten der Inhalt der Labels hinterher ebenfalls getauscht sein. Man beachte: „s1“ gehört immer zu Label1 und „s2“ gehört immer zu Label2. Wieso geschieht dies nicht?
Dies liegt, wie Sie sicher schon vermuten, an dem Zusatzwort „var“, welches ja zuerst vor den Parametern stand und das Sie entfernt hatten. Ohne dieses Schlüsselwort, wird in der Prozedur nicht mit den übergebenen Variablen selbst gearbeitet, sondern mit einer Kopie dieser Variablen. Dinge, die mit den Variablen in der Prozedur angestellt werden, haben also keine Auswirkung auf die Variablen im aufrufenden Programm. Diese Methode des Aufrufs nennt man „Call by Value„, weil mit dem Wert der Variable, aber nicht mit der Variable selbst gearbeitet wird.
Wenn Sie das Schlüsselwort „var“ hinzufügen, wird die Aufrufmethode geändert. Die Prozedur wird nun mittels „Call by Reference“ aufgerufen. Das heißt, nun wird nicht mehr nur mit dem Wert der übergebenenen Variable gearbeitet, sondern mit der Variable selbst. Es wird also eine Referenz auf die Variable als Parameter übergeben, also sozusagen ein „mit der da musst Du arbeiten“.
Und deswegen wird bei der Methode mit „Call by Reference“ auch die Beschriftung der Labels geändert, weil nämlich in der Prozedur mit den Variablen gearbeitet wird, die beim Button-Klick definiert wurden und nicht mit einer Kopie derselbigen.

Funktionen

Funktionen unterscheiden sich im Prinzip nur darin von Prozeduren, dass Funktionen einen Wert zurückliefern, also ein Ergebnis haben. Folgender Quelltext soll als Beispiel heran gezogen werden, welches zeigen soll, wie man Funktionen nutzt. Dabei wird das selbe Ergebnis einmal mit und einmal ohne Funktion realisiert. Zuest einnmal ohne eine Funktion:

var a, b, c, erg1, erg2, erg3: Integer;
begin
  erg1 := a*a*a*a + a*a*a + a*a + a;
  erg2 := b*b*b*b + b*b*b + b*b + b;
  erg3 := c*c*c*c + c*c*c + c*c + c;

  erg1 := erg1*erg1*erg1*erg1 + erg1*erg1*erg1 + erg1*erg1 + erg1;
  erg2 := erg2*erg2*erg2*erg2 + erg2*erg2*erg2 + erg2*erg2 + erg2;
  erg3 := erg3*erg3*erg3*erg3 + erg3*erg3*erg3 + erg3*erg3 + erg3;
end;

Und dann einmal mit Funktion:

function rechnen (wert : Integer) : Integer;
begin
  result := wert*wert*wert*wert + wert*wert*wert + wert*wert + wert;
end;

procedure TForm1.Button1Click(Sender: TObject);
var a, b, c, erg1, erg2, erg3: Integer;
begin
  erg1 := rechnen(a);
  erg2 := rechnen(b);
  erg3 := rechnen(c);

  erg1 := rechnen(erg1);
  erg2 := rechnen(erg2);
  erg3 := rechnen(erg3);
end;

Nun wird klarer, wie eine Funktion funktioniert. Die Funktion in diesem Beispiel heißt natürlich „rechnen“, was nicht sonderlich kreativ ist, aber für ein Beispiel ausreicht. Wie funktioniert nun aber diese Funktion?
Wenn man eine Funktion schreibt, gibt man zuerst einnmal an, dass es sich überhaupt um eine Funktion handelt. Dies macht man mit dem Wort „function“. Dann bestimmt man den Namen der Funktion. Und schließlich muss man noch angeben, welche Parameter eine solche Funktion hat.
Auch muss man angeben, was für einen Typ die Funktion zurückgibt, also welchen Typ das Ergebnis hat. Kommt am Ende ein String heraus, oder vielleicht doch ein Integer? Diesen Typ gibt man nach den Parametern an und zwar so, als wäre die Funktion eine Variable: man trennt den Rückgabetyp mit einem Doppelpunkt vom Rest und gibt dann den Typ an.
Um auf das oben genannte Beispiel zurückzukommen: der Name ist „rechnen“, der einzige Parameter ist „wert“ und ist vom Typ „Integer“, es wird ein Integer zurückgegeben. Der Parameter wird entsprechend der Formel mit sich selbst multipliziert (und ein bisschen addiert) und schließlich dem Ergebnis zugewiesen. Das Ergebnis verwendet man in der Funktion selbst wie eine Variable, sein Name als solche ist „result“. Eine Deklaration ist nicht erforderlich.
Im Hauptprogramm, welches die Funktion aufruft, kann man die Funktion fast so benutzen wie eine Variable desselben Typs. Man kann ihr natürlich keine Werte zuweisen. Außerdem sollte man sich im klaren darüber sein, dass eine Funktion jedesmal, wenn man sie in einer Formel benutzt, erneut aufgerufen wird. Ein Aufruf folgender Art macht dann wenig Sinn:

var ergebnis, a : Integer;
begin
  ergebnis := rechnen(a)*rechnen(a)*rechnen(a);
end;

Es würde dreimal hintereinander dieselbe Funktion mit demselben Parameter ausgeführt werden, was Rechenzeit kostet. Sinnvoller ist dieser Quelltext, bei dem das Ergebnis nur einmal ausgerechnet wird und dann in einer temporären Variable gespeichert wird.

var temp, ergebnis, a : Integer;
begin
  temp:=rechnen(a);
  ergebnis := temp*temp*temp;
end;

Warum Prozeduren und Funktionen?

Besonders beim letzten Beispiel wird klar geworden sein, weshalb eine Funktion Sinn macht: sie spart Arbeit. Aber das ist natürlich nicht alles, deswegen hier noch einmal eine Aufstellung der Vorteile von Funktionen und Prozeduren:

  • Wie schon gesagt kann eine Funktion oder Prozedur viel Arbeit sparen. Durch das Zusammenfassen von vielen Zeilen Code in nur einen Befehl reduziert sich die Tipparbeit enormn.
  • Viel wichtiger ist aber, dass der Quelltext dadurch auch übersichtlicher wird. Aber einer gewissen Länge und Verschachtelungstiefe (z.B. durch if-Anweisungen oder Schleifen) wird ein Quelltext schwer zu lesen und fehleranfällig. Funktionen und Prozeduren helfen, dies zu vermeiden.
  • Funktionen und Prozeduren sparen nicht nur beim erstmaligen Einsetzen Arbeit. Auch, wenn etwas am Programm geändert werden soll, machen sie dies einfacher. Wenn z.B. obige Berechnung oder der Vertauschungsalgorithmus falsch wären, müssten beide nur an einer Stelle geändert werden. Der Effekt würde überall dort eintreten, wo Funktion oder Prozedur aufgerufen werden. Das ist sehr wichtig, weil man dann nicht einen riesigen Haufen Code (okay, das Wortspiel war schlecht …) durchsuchen muss und evtl. doch eine Stelle übersieht.
  • Und zu guterletzt steigern Funktionen und Prozeduren die Wiederverwendbarkeit. Durch sie muss man einen Quelltext nur einmal schreiben und kann ihn dann in verschiedenen Programmen immer wieder einsetzen. So könnte man sowohl die Beispielprozedur als auch -funktion in anderen Programmen einsetzen, ohne sie noch einmal neu schreiben zu müssen.

Ich hoffe, durch diese Aufstellung ist klarer geworden, was Prozeduren und Funktionen zu einem unheimlich mächtigen Werkzeug macht. Und ebenso hoffe ich, dass Sie zu Ihrem und dem Wohl der Leute, die einmal ihren Quelltext lesen werden, reichlich gebrauch davon machen.

2 Gedanken zu „Delphi-Crashkurs“

  1. Guten Morgen,

    erst einmal vielen Dank für die ausführlichen Erklärungen!

    Im ersten Beispiel zur Darstellung von Zahlen im Rechner müsste es heißen

    4 mal 1 = 4*10^0

    statt

    4 mal 1    = 4*10

     

    1. Vielen Dank für den Hinweis.
      Ich habe es entsprechend korrigiert.
      Auch Deinen weiteren Hinweis habe ich eingearbeiotet.

Kommentare sind geschlossen.