Lazarus/Computer-Mathematik und Lazarus/Prozeduren, Funktionen und Bibliotheken: Unterschied zwischen den Seiten

Aus ZUM-Unterrichten
< Lazarus(Unterschied zwischen Seiten)
main>Peterdauscher
 
main>Peterdauscher
 
Zeile 1: Zeile 1:
{{Lazarus-Buch}}
{{Lazarus-Buch}}
"Computer" heißt wörtlich übersetzt "Rechner" und deshalb wäre es ja jetzt auch Zeit, ein Programm auch einmal etwas ausrechnen zu lassen.


Dafür muss das Programm drei Dinge tun:
== Prozeduren ==


*Die Zahlen, die verrechnet werden müssen, müssen von der Benutzeroberfläche eingelesen werden.
=== Einfache Prozeduren ===
*Die Zahlen müssen zu einem Ergebnis verrechnet werden.
*Das Ergebnis der Verrechnung muss auf der Benutzeroberfläche ausgegeben werden.


== Arbeiten mit eigenen Variablen ==
Wenn man Programme schreibt und immer mehr erweitert, so besteht die Gefahr, dass sie nicht nur immer größer sondern auch immer unübersichtlicher werden. Deshalb ist es sinnvoll, bestimmte, immer wiederkehrende Folgen von Befehlen mit einer bestimmten Bedeutung in einer Art selbst gebautem Befehl zusammenzufassen. Solche Befehle heißen auch '''Prozedur''' (engl.: '''procedure'''). Manche Leser werden den Sketch "Dinner for one" [https://de.wikipedia.org/wiki/Dinner_for_One] kennen, bei dem Butler James immer wieder fragt: "Same procedure as last year, Miss Sophie" und Miss Sophie jedes Mal antwortet "Same procedure as ''every'' year, James" . James und Miss Sophie meinen genau dasselbe wie wir: einen fest geregelten Ablauf von Dingen.


Bisher haben wir nur die Eigenschaften von bestimmten Komponenten geändert bzw. Dinge darin gespeichert, etwa die Beschriftung eines Buttons. Bei komplizierteren Programmen müssen wir aber auch andere Dinge speichern, Dinge die nicht unbedingt jeder gleich sehen muss.
==== Beispiel einer einfachen Prozedur ====
Hierfür gibt es so selbst definierte Variablen.


Jede Variable hat drei wichtige Punkte:
Ein sehr sehr einfaches Beispiel für eine Prozedur könnte ein Hinweis sein, der angezeigt werden soll, begleitet von einem hörbaren Signal. Das Programm benötigt lediglich einen Button mit dem Namen <tt>Button1</tt>.


* '''Name''': Jede Variable hat einen eindeutigen Namen, über den sie im Programm angesprochen werden kann.
{{kasten_blau|<source  line highlight="30-34,38" lang="pascal">
* '''Typ''': Wie schon bei den Eigenschaften von Komponenten haben auch Variablen verschiedene Typen: ganze Zahlen (integer), reelle Zahlen (real oder double), Zeichenketten (string) usw.
unit hinweis_geben;
* '''Wert''': In der Variablen gespeichert ist zu jeder Zeit ein ganz bestimmter Wert. Bei einer Variable vom Typ integer könnte das z.B. die Zahl 42 sein.
 
 
Um dem Computer mitzuteilen, dass es eine Variable <tt>zahl</tt> vom Typ <tt>integer</tt> geben soll, muss man die Variable ''deklarieren''.  Die Liste der Variablen eines Programms findet sich hinter dem Stichwort <tt>var</tt> im Programm. Dort ist in unserem Fall bereits die Variable Form1 deklariert. Dies ergänzen wir nun um unsere eigene Variable <tt>zahl</tt>
 
<source highlight="2" lang="pascal">
var Form1 : TForm1;
    zahl : integer;
</source>
 
Wie bei den Eigenschaften auch wird den Variablen im eigentlichen Programmtext zwischen <tt>begin</tt> und <tt>end;</tt> ein Wert über den ":="-Operator zugewiesen, etwa
<source lang="pascal">
zahl:=42;
</source>
 
Ein anschauliches Bild für die Variablen in einem Computerprogramm ist ein Schubladenschrank in der Küche. Der '''Wert''' einer Variable entspräche Inhalt einer solchen Schublade, der '''Name''' wäre etwa ein Etikett auf der Schublade. Um den Vergleich -- wenn auch etwas hinkend -- weiterzuführen, könnte der '''Typ''' der Variablen soetwas wie ein Schubladeneinsatz sein. Es gibt solche Einsätze für Dessertlöffel, aber z.B. auch für Münzgeld.
 
 
=== Einlesen von Integer-Variablen ===
 
Die Anweisung <tt>zahl:=42;</tt> weist der Variablen einen festen Wert, hier die 42 zu. Häufig braucht man jedoch Variablen, deren Wert vom Benutzer während der Laufzeit des Programms eingegeben werden, etwa über eine TEdit-Komponente. Gibt ein Benutzer über eine solche Kompoente eine Zahl ein, steht sie zunächst als Zeichenkette in der Eigenschaft <tt>Text</tt>. Aus dieser Zeichenkette z.B. in <tt>Edit1.Text</tt> muss jetzt eine "richtige" Zahl (z.B. vom Typ <tt>integer</tt>) werden.
 
Das besorgt der Befehl <tt>StrToInt</tt>:
<source lang="pascal">
a:=StrToInt(Edit1.Text);
</source>
 
Diese Zeile sorgt dafür, dass der Integer-Variablen <tt>a</tt> die Wert zugewiesen wird, die der Benutzer in das Edit-Feld <tt>Edit1</tt> geschrieben hat.
 
Bevor man jedoch der Variable <tt>a</tt> einen Wert zuweisen kann, muss der Computer wissen, dass es überhaupt eine Integer-Variable mit Namen <tt>a</tt> gibt.
 
Dies geschieht mit Hilfe einer so genannten Variablendeklaration:
 
 
Wichtig: Dieser Befehl steht noch vor dem <tt>Begin</tt>.
 
=== Rechnen mit Integer-Variablen ===
Nehmen wir an, wir hätten drei Integer-Variablen, <tt>a</tt>,<tt>b</tt> und <tt>c</tt>. Das Programm soll nun die Summe der Werte in <tt>a</tt> und <tt>b</tt> ausrechnen; das Ergebnis soll in der Variablen <tt>c</tt> gespeichert werden.
 
Dies erreicht man wieder mit einem Zuweisungsbefehl mit dem stilisierten Pfeil nach links:
<source lang="pascal">
c := a+b;
</source>
 
Natürlich gibt es neben der Addition von Integer-Zahlen auch andere Rechenoperationen:
 
{| class ="wikitable toptextcells"
! Rechenoperation
! Rechenzeichen <br />in der Sprache Pascal
! Beispiel
|-
| Addition || <nowiki>+</nowiki> || c:=a+b;
|-
| Subtraktion || <nowiki>-</nowiki> || c:=a-b;
|-
| Multiplikation || <nowiki>*</nowiki> || c:=a*b;
|-
| (ganzzahlige) Division|| <nowiki>div</nowiki> || c:=a div b;
|-
| Rest der (ganzzahligen) Division|| <nowiki>mod</nowiki> || c:=a mod b;
|}
 
Die ganzzahlige Division ist die Division, die die meisten von uns aus der Grundschule kennen:
 
<math>34 : 5 = 6 \text{ Rest } 4</math>
 
Den Wert "6" würde dann die Rechenoperation <tt>34 div 5</tt> liefern, den Wert "4" die Operation <tt>34 mod 5</tt>.
 
=== Ausgabe von Integer-Variablen ===
 
Bisher steht das Ergebnis nur in der Variable <tt>c</tt>. Der Benutzer des Programms sieht davon gar nichts. Der Wert muss noch irgendwie auf der Oberfläche erscheinen. Eine Möglichkeit dazu wäre, die Zahl in ein weiteres Edit-Feld zu schreiben:
 
<source lang="pascal">
Edit3.Text:=IntToStr(c);
</source>
 
=== Das ganze Programm zum Rechnen mit Integer-Zahlen ===
Das folgende Programm funktioniert, wenn es auf der Oberfläche die Komponenten <tt>Edit1</tt>, <tt>Edit2</tt> und <tt>Button1</tt> gibt.
{{kasten_blau|<source  line highlight="28-30,36-45" lang="pascal">
unit zahlen_main;


{$mode objfpc}{$H+}
{$mode objfpc}{$H+}
interface
interface
uses
uses
   Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls;
   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  ExtCtrls;


type
type
   { TForm1 }
   { TForm1 }


   TForm1 = class(TForm)
   TForm1 = class(TForm)
     Button1: TButton;
     Button1: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
     procedure Button1Click(Sender: TObject);
     procedure Button1Click(Sender: TObject);
   private
   private
Zeile 119: Zeile 30:
   public
   public
     { public declarations }
     { public declarations }
   end;  
   end;


var
var
   Form1: TForm1;  
   Form1: TForm1;
  a : integer;  // wir erfinden eine Zahlen-Variable a
  b : integer;  // wir erfinden eine Zahlen-Variable b
  c : integer;  // wir erfinden eine Zahlen-Variable c


implementation
implementation
{$R *.lfm}


{ TForm1 }
{ TForm1 }
procedure Hinweis;
begin
  Beep;
  ShowMessage('Sie haben den Knopf gedrückt');
end;


procedure TForm1.Button1Click(Sender: TObject);
procedure TForm1.Button1Click(Sender: TObject);
begin
begin
a:=StrToInt(Edit1.Text); // belege die Variablen
Hinweis;
b:=StrToInt(Edit2.Text);  // mit den Inhalten der Edit-Felder
end;
 
end.
 
</source>}}


c:=a+b; // Addiere a und b und weise den Wert der Variable c zu


Edit3.Text:=IntToStr(c);
Man sieht, dass es nach der Definition des eigenen Befehls (der Prozedur) "Hinweis" vollkommen genügt, diesen Befehl aufzurufen.


=== Prozeduren mit Wertparametern ===
Die oben gezeigte Prozedur tut immer genau das gleiche: Sie gibt das akustische Signal und den Hinweis "Sie haben den Knopf gedrückt". Häufig jedoch kommt es vor, das eine Prozedur zwar immer ähnliche, aber eben doch leicht verschiedene Dinge tun soll. So wäre es z.B. praktisch, wenn man den Hinweistext selbst immer wieder neu bestimmen könnte. Das funktioniert auch, wenn man der Prozedur einen so genannten Paramter mit auf den Weg gibt. Wir betrachten wiederum ein Beispiel:
{{kasten_blau|<source line start="30" highlight="1,9" lang="pascal">
procedure Hinweis(nachricht: string);
begin
  Beep;
  ShowMessage(nachricht);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Hinweis('Eine frei gewählte Nachricht');
end;
end;
</source>}}


initialization
Unterscheiden tun sich die gelb markierten Zeilen: Bei der Definition der Prozedur "Hinweis" in Zeile 30 ist hinter dem Namen der Prozedur noch in Klammern eine Variable angegeben, die in diesem Fall den Namen <tt>nachricht </tt> trägt und vom Typ <tt>string</tt> ist.
  {$I zahlen_main.lrs}
Wird nun in Zeile 40 der neue Befehl <tt>Hinweis</tt> aufgerufen, und zwar mit der Zeichenkette <tt>'Eine frei gewählte Nachricht'</tt> in Klammern, so wird die Variable <tt>nachricht</tt> mit diesem Wert belegt.
Wird nun innerhalb der Prozedur wiederum der Befehl ShowMessage mit <tt>nachricht</tt> als Parameter aufgerufen, so erscheint tatsächlich die Meldung mit dem richtigen Text auf dem Bildschirm.


end.
'''Wichtige Anmerkung:'''
Die Variable <tt>nachricht</tt> ist eine neue, eigenständige Variable. Beim Aufruf der Prozedur Hinweis wird ihr ein entsprechender Zeichenkettenwert zugewiesen. Wird dieser im Lauf der Prozedur verändert, so wirkt sich das auf das aufrufende Programm nicht aus.
 
=== Prozeduren mit Referenzparametern ===
 
Nun kann es sein, dass es der Zweck einer Prozedur sein soll, den Wert einer Variable im aufrufenden Programm aber tatsächlich zu ändern. Als Beispiel betrachten wir den (sehr sehr einfachen) Fall, bei dem der Wert einer Integer-Variable verdoppelt werden soll. Das Programm benötigt den Button <tt>Button1</tt> und das Edit-Feld <tt>Edit1</tt>. Der Vorspann mit Variablen usw. ist hier einfach einmal weggelassen; aber es ist klar, dass dort <tt> zahlenwert : integer;</tt> deklariert werden muss.
 
{{kasten_blau|<source line start="30" highlight="1,10" lang="pascal">
procedure verdopple (zahl : integer);
begin
zahl:=zahl*2;
end;
 
procedure TForm1.Button1Click(Sender: TObject);
begin
zahlenwert:=StrToInt(Edit1.Text);
verdopple(zahlenwert);
Edit1.Text:=IntToStr(zahlenwert);
end;
</source>}}
</source>}}


==Arbeiten mit Reellen Zahlen==
Beim Ausprobieren merkt man: Das Beispiel funktioniert offensichtlich nicht. Der Inhalt des Edit-Feldes bleibt beim Drücken des Knopfes genau gleich.
Das Arbeiten mit reellen Zahlen vom Typ <tt>real</tt> oder <tt>double</tt> funktioniert sehr ähnlich, mit ein paar kleinen Unterschieden:


Statt <tt>IntToStr</tt> und <tt>StrToInt</tt> werden hier die Befehle <tt>FloatToStr</tt> und sinnvollerweise <tt>format</tt> verwendet.
Wir müssen das Programm leicht abändern, damit es funktioniert. Wir fügen in Zeile 30 vor der Variable <tt>zahl</tt> das Schlüsselwort <tt>var</tt> ein. Das ist eigentlich ein wenig missverständlich, denn es soll bedeuten:
<tt>zahl</tt> ist '''keine''' eigenständige Variable sondern nur noch eine Art Spitzname für die Variable im Funktionsaufruf (man sagt auch: '''Referenz auf die Variable'''), in diesem Fall <tt>zahlenwert</tt>. Mit
<tt>zahl:=zahl*2</tt> wird jetzt in Wirklichkeit die Variable <tt>zahlenwert</tt> verdoppelt.


Die Zeile
{{kasten_blau|<source line start="30" highlight="1,9" lang="pascal">
<source lang="pascal">
procedure verdopple (var zahl : integer);
Edit3.Text:=format('%5.2f',[c]);
begin
</source>
zahl:=zahl*2;
sorgt dafür, dass die double-Variable <tt>c</tt> in das Edit-Feld geschrieben wird, dass sie insgesamt 5 Stellen und 2 Nachkommastellen hat.
end;


{{kasten_blau|<source  start=33 line highlight="1-14" lang="pascal">
procedure TForm1.Button1Click(Sender: TObject);
procedure TForm1.Button1Click(Sender: TObject);
var a : double; // wir erfinden eine Zahlen-Variable a
begin
    b : double; // wir erfinden eine Zahlen-Variable b
zahlenwert:=StrToInt(Edit1.Text);
    c : double; // wir erfinden eine Zahlen-Variable c
verdopple(zahlenwert);
Edit1.Text:=IntToStr(zahlenwert);
end;
</source>}}


begin
Durch diese kleine Änderung funktioniert jetzt das Programm tadellos.
a:=StrToFloat(Edit1.Text);  // belege die Variablen
b:=StrToFloat(Edit2.Text);  // mit den Inhalten der Edit-Felder


c:=a+b; // Addiere a und b und weise den Wert der Variable c zu
== Funktionen ==


Edit3.Text:=format('%5.2f',[c]);
Im Grunde würden Prozeduren mit Wert- und Referenzparametern vollkommen ausreichern, um immer wiederkehrende Abläufe in selbstdefinierte Befehle zu verpacken (Informatiker sprechen gerne auch von "'''verkapseln'''").


end;</source>
So könnte man zum Beispiel eine Prozedur zum Berechnen des Quadrats von integer-Zahlen schreiben. Das Beispielprogramm benötigt die Komponenten <tt>Button1, Edit1, Edit2</tt> und natürlich auch die Integer-Variablen <tt>zahlenwert</tt> und <tt>zahlenwertquadriert</tt>.
}}


Weitere Rechenoperationen für reelle Zahlen sind:
{| class ="wikitable toptextcells"
! Rechenoperation
! Rechenzeichen <br />in der Sprache Pascal
|-
| Exponentialfunktion|| <nowiki>exp(x)</nowiki>
|-
| Sinus-Funktion|| <nowiki>sin(x)</nowiki>
|-
| Cosinus-Funktion|| <nowiki>cos(x)</nowiki>
|-
| Tangens|| <nowiki>tan(x)</nowiki>
|-
| Natürlicher Logarithmus|| <nowiki>ln(x)</nowiki>
|}


Neben diesen mathematischen Funktionen gibt es noch jede Menge andere in Lazarus. Um diese jedoch verwenden zu können, muss in der Liste der so genannten Software-Bibliotheken noch die Bibliothek <tt>Math</tt> angegeben werden:
{{kasten_blau|<source line start="30" highlight="1,9" lang="pascal">
procedure quadrat(zahl : integer; var ergebnis: integer);
begin
ergebnis:=zahl*zahl;
end;


<source lang="pascal">
procedure TForm1.Button1Click(Sender: TObject);
uses Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls, Math;
begin
</source>
zahlenwert:=StrToInt(Edit1.Text);
quadrat(zahlenwert,zahlenwertquadriert);
Edit2.Text:=IntToStr(zahlenwertquadriert);
end;                          
</source>}}


{| class ="wikitable toptextcells"
Aber gerade im mathematischen Bereich ist das eher unüblich: außerdem muss man immer überlegen, welcher der beiden Parameter nun die eigentliche Zahl und welche das spätere Quadrat werden soll. Eleganter ist daher die folgende Schreibweise:
! Rechenoperation
! Rechenzeichen <br />in der Sprache Pascal
|-
| Umkehrfunktionen von trigonometrischen Funktionen || <nowiki>arcsin(x), arccos(x)</nowiki>
|-
| Logarithmus zur Basis 10 || <nowiki>log10(x)</nowiki>
|-
| Logarithmus zur Basis 2 || <nowiki>log2(x)</nowiki>
|-
| Logarithmus zu beliebiger Basis  || <nowiki>logn(basis,x)</nowiki>
|-
| Beliebige Potenz || <nowiki>power(basis,exponent)</nowiki>
|-
| Umrechnung von Bogenmaß nach Gradmaß|| <nowiki>radtodeg(x)</nowiki>
|-
| Umrechnung von Gradmaß nach Bogenmaß|| <nowiki>degtorad(x)</nowiki>
|}


Wichtig zu wissen ist bei den trigonometrischen Funktionen, dass sie immer von Angaben im Bogenmaß (statt 360° also <math> 2\pi</math> ausgehen. Angaben in Gradmaß müssen mit <tt>degtorad(x)</tt> umgerechnet werden.
{{kasten_blau|<source line start="30" highlight="1,9" lang="pascal">
function quadrat(zahl : integer) : integer;
begin
quadrat:=zahl*zahl;
end;


procedure TForm1.Button1Click(Sender: TObject);
begin
zahlenwert:=StrToInt(Edit1.Text);
zahlenwertquadriert:=quadrat(zahlenwert);
Edit2.Text:=IntToStr(zahlenwertquadriert);
end;                           
</source>}}


Welche Funktionen noch alle in "Math" enthalten sind, findet man unter <br />
== Bibliotheken ==
http://lazarus-ccr.sourceforge.net/docs/rtl/math/
Das Ausgliedern von immer gleichen Routinen in Prozeduren und Funktionen als eigene Befehle macht auch größere Programme übersichtlicher. Allerdings hilft bei sehr großen Programmen (mit mehreren Tausenden Zeilen) das auch nicht mehr so sonderlich viel. Deshalb kann man in diesem Fall Teile der Prozeduren und Funktionen in eigene Dateien ausladen, so genannte Bibliotheken, die in der Sprache Pascal auch als <tt>Units</tt> bezeichnet werden.


==Aufgaben==
Ein weiterer Vorteil von Bibliotheken ist, dass mehrere andere Programme die darin definierten Befehle benutzten Befehle verwenden können, ohne dass man die entsprechenden Funktionen und Prozeduren in das eigene Programm hineinkopieren muss. Vielmehr genügt es, in der Zeile <tt>uses ...</tt> den Namen der benutzten Unit anzugeben.
Eine solche Bibliothek haben wir im Kapitel [[../Computer-Mathematik/]] bereits kennen gelernt: die <tt>Unit Math</tt>, in der viele praktische mathematische Befehle definiert sind.


#Malermeister Klecksel muss zur Berechnung des ungefähren Verbrauchs an Farbe nach Angabe von Höhe, Breite und Länge eines Raums wissen <br /> a) Welche Fläche die Wände haben (Fenster spielen erst mal keine Rolle)<br /> b) Welche Fläche die Decke hat (wird manchmal in einer anderen Farbe gestrichen)<br />Entwickle eine geeignete komfortable Software!
== Aufgaben ==
#Eine lineare Funktion hat die Funktionsgleichung <math>f(x)=m \cdot x + n</math>. Schreibe ein Programm, bei dem man m, n und x eingeben kann und den Funktionswert erhält.
#Schreibe eine Prozedur, bei der Fläche und Umfang eines Rechtecks über Referenzparameter zurückgegeben werden. Länge und Breite sollen über Wertparameter in die Prozedur importiert werden. Teste die Prozedur in einem Programm.
#Schreibe ein Programm, das nach der Eingabe des Wertes für den Wert des Polynoms <math>x^2-8x+5</math> berechnet.
#Schreibe zwei Funktionen, die für ein Rechteck mit gegebener Länge und Breite die Fläche bzw. den Umfang ausrechnen und teste sie in einem Programm.  
#In Klasse 9 lernt man, wie man aus zwei Punkten und die Steigung einer Gerade durch diese beiden Punkte berechnet. <br />Schreibe ein Programm für einen Freund aus der 9. Klasse, der seine Hausaufgaben „kontrollieren“ will.<br />Zur Erinnerung: <math>m=\frac{y_2-y_1}{x_2-x_1}</math>
#Vergleiche die letzten beiden Aufgaben: Nenne Vor- und Nachteile der beiden Lösungen für das gleiche Problem.
#Erweitere das obige Programm, das aus den zwei gegebenen Punkten auch den y-Achsenabschnitt berechnet.
#Informiere Dich im Internet (oder Mathematikbuch) über den Höhensatz und den Kathetensatz. Kannst Du eine Reihe von sinnvollen Prozeduren bzw. Funktionen schreiben?
#Eine lineare Funktion hat die Funktionsgleichung <math>f(x)=m \cdot x + n</math>. Schreibe ein Programm, bei dem man m und n eingeben kann und das daraufhin die Nullstelle ausrechnet.
#Die Betragsfunktion in der Mathematik ist folgendermaßen definiert: Wenn eine Variable x einen Wert>=0 hat, so ist ihr Betrag genauso groß wie ihr Wert x. Hat sie dagegen einen negativen Wert, so ist der Betrag gerade -x. Konstruiere eine sinnvolle Funktion <tt>betrag(x)</tt>.
#Du kennst die p-q-Formel (oder auch a-b-c-Formel) zum Lösen quadratischer Gleichungen. Schreibe ein Programm, das nach Eingabe von q und q (bzw. a, b und c) die beiden Nullstellen der entsprechenden Funktion berechnet. Versuche einige Eingaben und überlege, ob es nicht Eingaben geben könnte, die Probleme verursachen.




{{Lazarus-Buch}}
{{Lazarus-Buch}}

Version vom 19. Januar 2014, 10:00 Uhr


Prozeduren

Einfache Prozeduren

Wenn man Programme schreibt und immer mehr erweitert, so besteht die Gefahr, dass sie nicht nur immer größer sondern auch immer unübersichtlicher werden. Deshalb ist es sinnvoll, bestimmte, immer wiederkehrende Folgen von Befehlen mit einer bestimmten Bedeutung in einer Art selbst gebautem Befehl zusammenzufassen. Solche Befehle heißen auch Prozedur (engl.: procedure). Manche Leser werden den Sketch "Dinner for one" [1] kennen, bei dem Butler James immer wieder fragt: "Same procedure as last year, Miss Sophie" und Miss Sophie jedes Mal antwortet "Same procedure as every year, James" . James und Miss Sophie meinen genau dasselbe wie wir: einen fest geregelten Ablauf von Dingen.

Beispiel einer einfachen Prozedur

Ein sehr sehr einfaches Beispiel für eine Prozedur könnte ein Hinweis sein, der angezeigt werden soll, begleitet von einem hörbaren Signal. Das Programm benötigt lediglich einen Button mit dem Namen Button1.

Vorlage:Kasten blau


Man sieht, dass es nach der Definition des eigenen Befehls (der Prozedur) "Hinweis" vollkommen genügt, diesen Befehl aufzurufen.

Prozeduren mit Wertparametern

Die oben gezeigte Prozedur tut immer genau das gleiche: Sie gibt das akustische Signal und den Hinweis "Sie haben den Knopf gedrückt". Häufig jedoch kommt es vor, das eine Prozedur zwar immer ähnliche, aber eben doch leicht verschiedene Dinge tun soll. So wäre es z.B. praktisch, wenn man den Hinweistext selbst immer wieder neu bestimmen könnte. Das funktioniert auch, wenn man der Prozedur einen so genannten Paramter mit auf den Weg gibt. Wir betrachten wiederum ein Beispiel:


Vorlage:Kasten blau

Unterscheiden tun sich die gelb markierten Zeilen: Bei der Definition der Prozedur "Hinweis" in Zeile 30 ist hinter dem Namen der Prozedur noch in Klammern eine Variable angegeben, die in diesem Fall den Namen nachricht trägt und vom Typ string ist. Wird nun in Zeile 40 der neue Befehl Hinweis aufgerufen, und zwar mit der Zeichenkette 'Eine frei gewählte Nachricht' in Klammern, so wird die Variable nachricht mit diesem Wert belegt. Wird nun innerhalb der Prozedur wiederum der Befehl ShowMessage mit nachricht als Parameter aufgerufen, so erscheint tatsächlich die Meldung mit dem richtigen Text auf dem Bildschirm.

Wichtige Anmerkung: Die Variable nachricht ist eine neue, eigenständige Variable. Beim Aufruf der Prozedur Hinweis wird ihr ein entsprechender Zeichenkettenwert zugewiesen. Wird dieser im Lauf der Prozedur verändert, so wirkt sich das auf das aufrufende Programm nicht aus.

Prozeduren mit Referenzparametern

Nun kann es sein, dass es der Zweck einer Prozedur sein soll, den Wert einer Variable im aufrufenden Programm aber tatsächlich zu ändern. Als Beispiel betrachten wir den (sehr sehr einfachen) Fall, bei dem der Wert einer Integer-Variable verdoppelt werden soll. Das Programm benötigt den Button Button1 und das Edit-Feld Edit1. Der Vorspann mit Variablen usw. ist hier einfach einmal weggelassen; aber es ist klar, dass dort zahlenwert : integer; deklariert werden muss.

Vorlage:Kasten blau

Beim Ausprobieren merkt man: Das Beispiel funktioniert offensichtlich nicht. Der Inhalt des Edit-Feldes bleibt beim Drücken des Knopfes genau gleich.

Wir müssen das Programm leicht abändern, damit es funktioniert. Wir fügen in Zeile 30 vor der Variable zahl das Schlüsselwort var ein. Das ist eigentlich ein wenig missverständlich, denn es soll bedeuten: zahl ist keine eigenständige Variable sondern nur noch eine Art Spitzname für die Variable im Funktionsaufruf (man sagt auch: Referenz auf die Variable), in diesem Fall zahlenwert. Mit zahl:=zahl*2 wird jetzt in Wirklichkeit die Variable zahlenwert verdoppelt.

Vorlage:Kasten blau

Durch diese kleine Änderung funktioniert jetzt das Programm tadellos.

Funktionen

Im Grunde würden Prozeduren mit Wert- und Referenzparametern vollkommen ausreichern, um immer wiederkehrende Abläufe in selbstdefinierte Befehle zu verpacken (Informatiker sprechen gerne auch von "verkapseln").

So könnte man zum Beispiel eine Prozedur zum Berechnen des Quadrats von integer-Zahlen schreiben. Das Beispielprogramm benötigt die Komponenten Button1, Edit1, Edit2 und natürlich auch die Integer-Variablen zahlenwert und zahlenwertquadriert.


Vorlage:Kasten blau

Aber gerade im mathematischen Bereich ist das eher unüblich: außerdem muss man immer überlegen, welcher der beiden Parameter nun die eigentliche Zahl und welche das spätere Quadrat werden soll. Eleganter ist daher die folgende Schreibweise:

Vorlage:Kasten blau

Bibliotheken

Das Ausgliedern von immer gleichen Routinen in Prozeduren und Funktionen als eigene Befehle macht auch größere Programme übersichtlicher. Allerdings hilft bei sehr großen Programmen (mit mehreren Tausenden Zeilen) das auch nicht mehr so sonderlich viel. Deshalb kann man in diesem Fall Teile der Prozeduren und Funktionen in eigene Dateien ausladen, so genannte Bibliotheken, die in der Sprache Pascal auch als Units bezeichnet werden.

Ein weiterer Vorteil von Bibliotheken ist, dass mehrere andere Programme die darin definierten Befehle benutzten Befehle verwenden können, ohne dass man die entsprechenden Funktionen und Prozeduren in das eigene Programm hineinkopieren muss. Vielmehr genügt es, in der Zeile uses ... den Namen der benutzten Unit anzugeben. Eine solche Bibliothek haben wir im Kapitel Computer-Mathematik bereits kennen gelernt: die Unit Math, in der viele praktische mathematische Befehle definiert sind.

Aufgaben

  1. Schreibe eine Prozedur, bei der Fläche und Umfang eines Rechtecks über Referenzparameter zurückgegeben werden. Länge und Breite sollen über Wertparameter in die Prozedur importiert werden. Teste die Prozedur in einem Programm.
  2. Schreibe zwei Funktionen, die für ein Rechteck mit gegebener Länge und Breite die Fläche bzw. den Umfang ausrechnen und teste sie in einem Programm.
  3. Vergleiche die letzten beiden Aufgaben: Nenne Vor- und Nachteile der beiden Lösungen für das gleiche Problem.
  4. Informiere Dich im Internet (oder Mathematikbuch) über den Höhensatz und den Kathetensatz. Kannst Du eine Reihe von sinnvollen Prozeduren bzw. Funktionen schreiben?
  5. Die Betragsfunktion in der Mathematik ist folgendermaßen definiert: Wenn eine Variable x einen Wert>=0 hat, so ist ihr Betrag genauso groß wie ihr Wert x. Hat sie dagegen einen negativen Wert, so ist der Betrag gerade -x. Konstruiere eine sinnvolle Funktion betrag(x).