Home | Computer | Pascal Kurs | Site Map |
Bisher haben wir alles in das Hauptprogramm gepackt. Das ging bei unseren kleinen Programmen, aber für größere Programme ist das doch sehr unübersichtlich. Daher gibt es zwei Möglichkeiten Unterprogramme in Pascal zu realisieren.
Eine Funktion gibt einen Wert zurück, denn man z.B. in einer Zuweisung benutzen kann. Turbo Pascal verfügt zahlreiche Funktionen. Die sie nutzen können ohne Sie zu schreiben. So übergibt folgende Funktion den Sinus des Winkels:
Wert:=sin(Winkel);
Der Funktion sin wird ein Wert übergeben der in den Klammern steht. Es gibt auch Funktionen ohne Werte:
taste=Readkey;
liest ein Zeichen von der Tastatur ein und übergibt es als Ergebnis an die Variable Taste. Prozeduren unterscheiden sich formal von Funktionen nur dadurch das Sie keinen Rückgabewert haben. Sie haben schon die Prozeduren Readln und Writeln benutzt. Da Prozeduren etwas einfacher zu verstehen sind als Funktionen, beginnen wir mit Ihnen.
Eine Prozedur ist in Pascal ein Unterprogramm und sie hat einen Namen mit einer Parameterliste und dann die Variablen, Konstanten, Typen und Code wie das Hauptprogramm, d.h. es können Konstanten und Variablen definiert werden, aber auch eigene Typen. (Zu Typen später mehr). Eine Prozedur ist also ein "Programm im Programm". Deswegen gibt es auch eine Besonderheit die sehr wichtig ist: Sie betrifft die in einer Prozedur definierten Variablen und Konstanten. Diese sind nun lokal. D.h. nur innerhalb der Prozedur, nicht aber in anderen Prozeduren bekannt.
Wenn man im Hauptprogramm eine Variable × definiert und in einer Prozedur auch eine Variable x, so betreffen alle Änderungen nur die lokale Variable, nicht die des Hauptprogramms. Dies gilt allgemein: Eine lokal definierte Variable "verdeckt" eine globale Variable.
Jede Prozedur kann wiederum eigene Prozeduren und Funktionen enthalten, sie müssen nur von dem Codeblock erscheinen. Auch hier gilt: Diese Funktionen/Prozeduren sind nur innerhalb dieser Prozedur bekannt und nicht außerhalb. Dies ist ein wichtiger Unterschied zu C, welches nur global sichtbare Funktionen kennt.
Allgemeine Form einer Prozedur Definition:
Procedure namen(Parameterliste);
Const Konstanten;
Var Variablen;
type Typen;
... eigene Funktionen und Prozeduren...
begin
...Code;
end;
Vorgeschrieben sind nur der Name und der Codeblock, d.h. folgendes ist die einfachste Prozedur:
Procedure tue_nichts;
begin
end;
Für Variablen, Typen und Konstanten gilt: Ab der Definition sind sie bekannt, bis die Prozedur endet. Folgen weitere (Unter) Prozeduren so kennen diese auch die Variablen. Variablen können in Prozeduren gleiche Namen wie globale Variablen haben. Sie verdecken diese dann. D.H. man kann nicht auf die globalen Variablen zugreifen. Anders als globale Variablen verlieren sie aber den Wert, sobald man die Prozedur verlässt. Man kann sich also nicht sicher sein, das der Wert erhalten bleibt. Man kann dies durch konstante Variablenparameter umgehen, die sozusagen das Gegenstück zu den static Variablen in C sind. die man aber nicht so häufig wie in C braucht, da Pascal eine bessere Rückgabemöglichkeit für Parameter hat.
Ein Beispiel:
const MaxX=100;
MaxY=200;
type Feldtyp = Array [1..MaxX,1..MaxY] of word;
function Suche_Maximum(const Feld: Feldtyp): word;
Var i: 1..MaxY;
erg: Word;
function Suche_Maxx(const y: integer): word;
var erg: word;
i: 1..maxx;
begin
erg:=0;
for i:=1 to maxx do if feld[y,i]>erg then erg:=feld[y,i];
Suche_Maxx:=erg;
end;
begin
erg:=0;
for I:=1 to maxy do
if Suche_maxx(i)>erg then erg:=Suche_maxx(i);
Suche_maximum:=erg;
end;
In diesem etwas komplexeren Beispiel (das auch einiges enthält was wir noch nicht besprochen
haben) achten Sie bitte nur auf die Variablen: Feld ist auch in der eingebetteten Prozedur
Suche_maxx sichtbar, genauso wie die globale Konstante Maxx. Die lokalen Variablen i
und erg verdecken aber die der Funktion Suche_maximum. D.h. Suche_maxx hat ein eigenes i und
erg und verändert das von Suche_maximum nicht. Nur so kann ein i über den X Wertebereich und das
andere über den Y Wertebereich laufen.
Wie sieht es nun mit den Parametern aus, die man in den Klammern übergibt? Eigentlich nicht anders als wenn man Variablen definiert: Es muss der Typ angegeben werden und ein Name, unter dem der Parameter in der Prozedur benutzen kann. Mehrere gleiche Parameter trennt man durch Komma und verschiedene durch Semikolon:
Procedure Kreis(Integer x,y; Double radius);
ist eine Prozedur mit 3 Parametern: Zwei Ganzzahlen für die Koordinaten und einer Flieskommazahl. Man kann diese Prozedur so aufrufen:
Kreis(10,10,r);
Danach haben innerhalb der Prozedur Kreis × und y je den Wert 10 und Radius den Wert von r. Beim Aufruf muss man natürlich nicht den Typ angeben und kein Semikolon, sondern trennt alle Parametern mit Kommas. Die Typen der Parameter müssen aber stimmen. Man kann zwar Zahlen umwandeln, aber man könnte Kreis nicht mit 3 Variablen des Typs Char aufrufen.
Wichtig: Es gibt 3 Typen von Parametern! Pascal bietet anders als Java oder C drei Schnittstellen zur Übergabe von Parametern an:Die Parameter die bisher übergeben wurde sind Wert Parametern, dass sind alle Parameter wenn nicht die Schlüsselwörter der beiden folgenden Fälle VAR und CONST dazugestellt werden. Wertparameter (englisch: Call by Value) übergeben den Wert, aber nicht die Variable selbst. Würde unsere Funktion Kreis z.B. den Parameter Radius ändern, so ändert das nicht den Wert der aufrufenden Variable r. Zahlen oder andere Konstanten kann man nur an Wertparameter übergeben. Ein Variablenparameter benötigt dagegen immer eine Variable als Übergabeparameter. Man verwendet diese Art von Parametern wenn man sagen will: OK Funktion mach bitte dies und das mit folgenden Werten. Alle Mathematischen Funktionen errechnen z.B. ein Ergebnis, beeinflussen aber nicht die übergebenen Werte. Hier können die Parameter auch Ausdrücke sein, zum Beispiel:.
Pos('"',Zeile);
oder
a:=sin(pi/4);
Dies ist möglich weil die Prozedur eine Kopie erhält, denn ein Ausdruck hat keine Adresse wie sie bei Variablenparametern übergeben werden.
Setzt man vor den Namen eines Parameters ein VAR so ist es ein Variablenparameter.(englisch: Call by reference). Hier übergibt man die Variable direkt. Ändert man den Wert eines Parameters, so führt man diese Änderung auch am Original aus Bsp.:
VAR eins: Integer;
zwei: Single;
Procedure Daemlich(Var Veraendern: Integer; Bleibt_so: Integer);
begin
veraendern:=2;
bleibt_so:=4;
end;
begin
eins:=1;
zwei:=2;
Daemlich(eins,zwei);
end.
Daemlich hat zwei Parameter. Der erste Parameter ist ein Variablenparameter. Die Änderung in
der Prozedur bewirkt das jeder Aufruf von Daemlich(eins,zwei) bewirkt das eins den Wert 2
bekommt. Zwei dagegen wird nie durch "Daemlich" verändert. Bitte beachten Sie auch folgendes:
Damit man VAR und normale Parameter in Daemlich benutzen kann habe ich
beide durch ein Semikolon getrennt. VAR Veraendern, Bleibt_so: Integer)
hätte zwei VAR (Variablen) Parameter definiert. Außerdem ist nun der Typ
wichtig. Man kann einem VAR Parameter nur eine Variable übergeben,
keine Konstante oder Ausdrücke und es muss derselbe Typ sein, also hier Integer. Der Aufruf von
Daemlich (zwei,eins) ergibt einen Fehler, da Zwei vom Typ Single ist.
Da man bei Variablenparametern keine Kopie sondern die Adresse der Variable übergibt sollte man große Strukturen (Arrays etc.). nur so übergeben, auch wenn man sie nicht verändert - der Code ist schneller und spart Speicherplatz. Zum Typ ist noch zu sagen, das Turbo Pascal es hier bei den Standardtypen locker nimmt: Definiert man eine Routine wie
Function Suche(VAR Ergebnis: LongInt): Boolean;
So kann der übergebene Parameter von jedem Integertyp sein, also auch Byte, Word... Klar ist natürlich, das der Wertebereich erhalten bleibt: Eine übergebene Byte Variable bekommt Probleme wenn man in dieser Function Suche schreibt:
Suche:=1234;
Da der Wertebereich von Byte bei 255 endet (Sie würden den Wert modulo 256 enthalten also hier 210 (210 + 4*256 = 1234). Bei Strings kann man durch Compilerschalter beeinflussen, ob nur gleich lange Strings erlaubt sind oder sie einfach abgeschnitten werden. Bei eignen Typen tragen Sie aber die Verantwortung:
Type
Zeichen1 = ['A'..'Z'];
Zeichen2 = ['A'..'Z'];
Var
a: Zeichen1;
b: Zeichen2;
procedure dummy(Var x: Zeichen1);
begin
end;
begin
dummy(a);
dummy(b); {Hier gibt es einen Compilerfehler}
end...
läuft nicht. Zeichen1 und Zeichen2 sind zwei benutzerdefinierte Typen , die zufällig die
gleiche Zeichenmenge enthalten. Bei Benutzerdefinierten Typen ist der Compiler streng. Auch
wenn in diesen beiden Typen eigentlich dieselben Elemente enthalten sind. Dasselbe schlägt
auch zu, wenn man geschrieben hätte:
Var a: 'A'..'Z';
b: 'A'..'Z';
Erst ab Turbo Pascal 7.0 gibt es den Konstantenparameter. Es ist ein Parameter der von der Prozedur nicht verändert werden darf. Er wird durch ein CONST vor dem Namen angezeigt. Das erzeugt etwas schnelleren Code, wenn es sich nicht um einfache sondern komplexere Typen (Strings, Rekords, Arrays...) handelt. Vor allem aber ist es eine Möglichkeit Programmierfehler zu erkennen, da der Compiler Zuweisungen an Konstantenparameter bemäkelt. Für die Praxis kommt man aber auch gut mit normalen Wertparametern aus. (In C ist Const erheblich wichtiger, da es dort keine VAR Parameter gibt und man so alle VAR Parameter mit Zeigern emulieren muss). Trotzdem sollten sie immer Const verwenden wenn sie ihrer Funktionen einen Parameter als Information übergeben, z.B. als Grenze, als Index oder Argument. Es ist verlockend eine lokale Variable einzusparen, und den Wertparameter zu verändern. Doch das ist kein guter Stil und fehleranfällig
function Kleinbuchstabe(buchstabe : char): boolean;
begin
if (buchstabe>='a') and (buchstabe<='z') then kleinbuchstabe:=true
else kleinbuchstabe:=false;
end;
VAR zeichen : char;
begin
zeichen:='g';
writeln(kleinbuchstabespan class=
"c12">(zeichen));
end.
Hier sieht man alle Änderungen: Anstatt Procedure erscheint nun function als Schlüsselwort. Der Rückgabetyp wird mit einem Doppelpunkt an die Parameterliste angeschlossen. Der Rückgabewert wird zugewiesen indem man dem Funktionsnamen einen Wert zuweist. Man kann also den Funktionsnamen als eine Variable des Rückgabetyps betrachten, bei Kleinbuchstaben also als eine Boolean Variable. Anders als in C kann man beliebig oft einen Wert zuweisen, jeweils der letzte wird bei Funktionsende zurückgeben. Auch wird bei Zuweisung nicht die Funktion verlassen. Nur Vorsicht: Eine Abfrage/i> des Wertes der Funktion bewirkt ein erneutes Aufrufen der Funktion. Man nennt dies Rekursion:
Function add100 : integer;
VAR c : integer;
begin
c:=add100;
ad100:=c+100;
end;
ist ein korrekter Code, der jedoch in einer Endlosschleife endet. In der Zeile c:=add100 wird nicht c der Aktuelle Wert von ad100 zugewiesen sondern es wird die Funktion add100 erneut aufgerufen, in der wiederum derselbe Fehler passiert, das geht so oft bis der Computer keinen Speicher mehr hat und einen Fehler meldet. Die ganze Verwechslung ist aber nur bei Funktionen mit keinem Parameter möglich, da man sonst bei einem Aufruf die Parameterliste übergeben müsste. Bei Delphi und auch FPK und VP gibt es noch die interne Variable Result, der man Werte zuweisen und die man abfragen kann. Ihr Wert wird am Funktionsende übergeben. Anders als beim Funktionsnamen ist es so möglich auch Werte abzufragen, und so auf eine Zwischenvariable zu verzichten.
Eine Funktion nehmen Sie immer dann, wenn sie einen und zwar genau einen Rückgabewert brauchen. Paradebeispiel sind mathematische Funktionen. Mehrere Parameter verwirklichen sie mit Prozeduren mit mehreren VAR Parametern. Wenn ihre Funktion aber auch Probleme haben kann, dann macht man es oft so, das die Funktion nur einen Boolean Rückgabewert hat, der z.B. false ist wenn es Probleme gab und das eigentliche Ergebnis steckt dann in einem VAR Parameter.
Wenn Sie mit einem 16 Bit System arbeiten (Turbo Pascal 1-7, Delphi 1), so werden sie bei größeren Programmen feststellen, das der Speicher begrenzt ist. Max. 64 KByte sind für Variablen möglich. Dies gilt aber Gott sei Dank nur für jeweils einen Block, d.h. das Hauptprogramm kann 64 K haben, jede einzelne Funktion aber auch 64 K. Braucht man mehr so kann man dynamisch Variablen erzeugen, dann belegt ein Pointer 4 Byte und kann wiederum auf 64 K zeigen. (dazu in späteren Kapiteln mehr). Einschneidender ist aber die Einschränkung, dass eine Struktur max. 64 K Belegen kann. z.B.:
VAR Editor = Array [1..1000] of String[80];
gibt Probleme, da das Array insgesamt 80 Kilobyte belegt (1000 × 80) und so die 64 K Grenze überschreitet. Auch wenn man auf eigene Routinen ausweicht und Speicher dynamisch holt (mehr dazu in den folgenden Teilen), bleibt diese Grenze bestehen. Sie können also nie eine Datenstruktur erzeugen die größer als 64 K ist z.B. um ein Bild darin zu speichern. Hier gibt es eigentlich nur einen Ausweg: Aufsteigen auf ein 32 Bit System (FPK, VP, Delphi 2 aufwärts). /p>
Bisher haben wir Variablen benutzt die einen Typ hatten, wir können aber auch eigene Typen definieren. Ein Typ ist praktisch eine Schablone. Man sagt: Ich will Variablen haben und die sollen alle gemeinsame Merkmale haben. Ein Typ ist aber keine Variable, sondern eine Variable kann erzeugt werden, wenn man den Typ definiert hat. Der Typ ist also praktisch eine Vereinbarung, während eine Variable immer mit konkreten Werten belegt werden kann. Es gibt in Pascal mehrere Typen die wir sukzessiv kennen lernen, hier eine Einführung in die Typendefinition. Sie beginnt mit dem Wort Type und einer Definition ähnlich wie bei einer Konstante in der Form:
NeuerTyp = Typart;
Sie können damit z.B. Typen umdefinieren: /p>
Type Single = Double;
würde bewirken, dass sie auch dann mit Doppelter Genauigkeit rechnen wenn Sie eine Single Variable benutzen. Sie haben Single als Double umdefiniert. Wichtiger sind aber drei neue Typen:
Type
Aufzaehlungstyp = (Bube,Dame,Koenig,Ass);
Grussbuchstabentyp = 'A'..'Z';
Grossbuchstabenmenge = Set of Grussbuchstabentyp;
VAR
Karte: Aufzaehlungstyp;
Buchstabe: Grussbuchstabentyp;
zeichen = Grossbuchstabenmenge;
Dies zeigt alle 3 Typen und ihre Benutzung. TYPE legt nur den Typ fest, erst mit VAR kreieren
sie eine Variable mit diesem Typ. Sie hätten auch schreiben können:
Karte: (Bube,Dame,Koenig,Ass);
Das hätte aber den Nachteil, das Sie bei einer zweiten Definition
Karte2: (Bube,Dame,Koenig,Ass);
zwar eine neue Variable haben, aber diese haben nicht denselben Typ, eine Zuweisung Karte:=Karte2 ergibt einen Fehler. Leider eine der wenigen Unstimmigkeiten in Pascal. So ist es sinnvoll alle benötigte Typen zu deklarieren und diese dann für die Variablen zu verwenden. Da eine Typdeklaration nur wichtig für den Compiler ist, keinen Speicher belegt und keine Prozessorzeit benötigt spricht nichts dagegen am Kopf des Programms alle Typen die man braucht zu deklarieren und dann nur noch mit dem Typnamen zu arbeiten. Wenn sie später auch wissen was Units sind bietet es sich an solche Typen und Konstanten in eine eigene Unit auszulagern. Dann stehen sie allen benötigten Programmteilen durch Einbinden zur Verfügung.
Der erste Typ ist ein Aufzählungstyp. Er erlaubt es der Variable Karte einer der 4 Werte die angegeben sind zuzuweisen. Das hat eine enorme Verbesserung der Lesbarkeit zur Folge z.B. im Programmtext:
if karte=Ass then...
Man kann mit der Funktion Ord(variable) herausfinden welche Nummer der Wert hat. Diese werden von 0 durchgezählt und Ass hätte so die Nummer 3.
Der Teilbereichstyp 'A'..'Z' ist eine Untermenge eines anderen Typs, z.B. hier Char. Wozu das werden Sie fragen? Nun zum einen macht es den Programmtext erklärender. Zeichen: 'a'..'z' zeigt, das es sich bei dieser Variable nicht nur um eine Char Variable handelt, sondern auch nur Kleinbuchstaben als Werte zulässig sind. Zudem kann der Compiler bei der Laufzeit Überschreitungen feststellen, wenn man dies wünscht - sehr geschickt für das Debuggen. Die Zuweisung von "#" an Zeichen ist möglich, denn es ist ja eine Char Variable, aber es sprengt den angegebenen Wertebereich und wenn man wünscht, sagt einem das der Compiler. (Und das auch noch zur Laufzeit)
Mit dem Wort span class="c14">SET OF definieren Sie eine Menge eines anderen Typs. Bislang konnte jeder Typ nur einen Wert annehmen: Großbuchstabe z.B. nur ein 'A', aber nicht gleichzeitig den Wert 'A' und 'F'. Bei dem Mengentyp ist dies nicht so. Die Großbuchstabenmenge kann die Summe aller Werte von 'A' bis 'Z' - also 26 Stück annehmen. Die Klammern kennzeichnen dies als eine Menge (Sie kommen auch noch als Array Klammern vor).
Man wird dies einsetzen wenn ein Wert nicht nur eine Option hat, sondern mehrere. Sie kennen das von den Kästchenbuttons in Windows, hier können Sie auch mehrere Optionen mit einem Kreuz markieren.
Für Mengen gibt es eigene Rechenoperationen: + für die Vereinigungsmenge und - für die Differenzmenge. Besonders häufig - auch ohne Mengendefinition - braucht man den Operator IN::
if (Menueoption in ['0'..'9','ä','ü','ö']) then
führt den THEN Zweig genau dann aus, wenn Menueoption einen der angegebenen Werte hat und erspart einem so einen ganzen Wust von CASE oder IF THEN Abfragen, die in C nötig wären. Da '+' und '-' nun mit Mengen arbeiten muss man nun auch einzelne Werte in den eckigen Klammern setzen.:
Menueoption:=Menueoption+ ['5'];
Menueoption:=Menueoption-['ä'..'ü'];
Fügt 5 zur Menge hinzu und entfernt die Elemente 'ä','ö' und 'ü' aus der Menge. Die beiden Punkte.. geben einen Teilbereich an, also von..bis (einschließlich). Man verwendet sie auch sonst bei Arrays für die Dimensionen,
VAR
String1 : String [80];
String2 : String;
CCONST
vordef_string String[70] = 'Hallo!';
String1 ist eine Zeichenkette von maximal 80 Zeichen Länge - mehr wird abgeschnitten. String2 ist eine Zeichenkette mit der maximalen Länge von 255 Zeichen. Gibt man keine Längenangabe an so wird die maximale Länge angenommen und das sind 255 Zeichen. Mehr geht unter Turbo Pascal 1-7 nicht. 32 Bit Systeme wie Delphi 2.., VP und FPK sprengen diese Grenze und erlauben bis zu 2 Gigabyte für einen String. Da diese genauso wie kurze Strings funktionieren, gehe ich darauf nicht ein, alles was hier über die kleinen Strings gesagt wird ist auch auf die langen übertragbar. Diese sind auch nicht solche Speicherfresser wie die hier vorgestellten statischen Strings. (Jeder String belegt bei Turbo Pascal soviele Bytes wie hier angegeben, egal ob nur ein Teil belegt ist. Bei den 32 Bit Systemen belegt ein String nur soviele Bytes wie er lang ist).
Wichtig ist, das ein String immer ein Byte mehr als die angegebene Länge belegt. Der String1 also 81 Byte. Egal ob der String leer ist oder 80 Zeichen enthält, er belegt immer 80 Bytes, also wenn Sie wissen das sie nie mehr als 20 Byte benötigen so definieren Sie nur einen String[20]. Bei Variablenparametern kann man dem Compiler sagen ob er nur Strings zulässt die dieselbe Länge haben oder nicht. Es macht wenig String einer Prozedur die das 40.ste Zeichen eines Strings verändern will einen String mit 20 Zeichen Länge zu übergeben.... Es ist deswegen nicht dumm im Typenteil eigene Stringtypen zu definieren:
type
Zeilentyp String [80];
Worttyp String[20];
VAR
zeile : Zeilentyp;
wort : Worttyp;
Sie können, um auf ein bestimmtes Zeichen innerhalb eines Strings zuzugreifen, diesen als ein ARRAY of CHAR mit der angegebenen Maximallänge interpretieren:
Wort[9]:='c';
{interpretiert Worttyp als Array [1..20] of Char}
Jedes Zeichen hat einen Index der von 1 ausgeht und bis zur deklarierten Maximallänge geht. Im Zeichen 0 steht die Länge. Sie sollten jedoch verzichten diese direkt zu manipulieren (ich habe das auch so gemacht und dann unter Delphi sehr merkwürdige Probleme gehabt, da dort die Strings anders organisiert sind...). Strings sind zueinander zuweiskompatibel, d.h. sie können auch schreiben: Wort:=zeile. In diesem Fall enthält Wort aber nur die ersten 20 Zeichen von Zeile, ist ja klar, mehr geht nicht rein!.
Mehr über Stringfunktionen und weitere Funktionen und Prozeduren erfahren Sie in der Online Hilfe von ihrem Pascal Compiler.(Shift-F1). Insgesamt ist das String Handling in Pascal sehr viel komfortabler als in C. Vor allem können sie nicht andere Speicherbereiche überschreiben. Es ist also problemlos möglich einem String[4] den String 'Hallo'+'Du Da!' zuzuweisen. Es steht eben dann nur "Hall" da drinn. IN C/C++ hätten sie die darauf folgende Variable auch überschrieben. Es gibt eine Ausnahme bei 32 Bit Systemen. Wenn sie die Strings als Arrays dort bearbeiten, also z.B Zeile[5]:='4'; dann verlassen Sie den sicheren Boden der Stringfunktionen und müssen gewährleisten, das in diesem Fall der String auch mindestens 5 Zeichen lang ist. Dies macht man meistens über eine Wächterabfrage mitels Length.
type farben Karo,Pik,Herz,Kreuz)
VAR
Speicher : [Array [1000..2000] of Byte;
trumpf : Array [farben] of Aufzaehlungstyp;
Sie sehen das der Index nicht bei 0 anfangen muß und auch eine Teilbereich oder Aufzählungstyp als Index dienen kann. Das macht Pascalprogramme gut verständlich. Mit dieser Definition wäre z.B. folgendes möglich:
Trumpf[Herz]:=Koenig;
if Trump(Pik]=Ass then ...
- ist doch sofort verständlich oder?
Mehrere Dimensionen erreicht man durch mehrere Teilbereiche durch Kommas getrennt:
Wuerfel: [1..5,0..4,10..20] of Double;
legt ein Array mit 5 × 5 × 11 Elementen fest. Der Zugriff auf ein Element geht so:
Wuerfel[1,0,12]:=pi;
oder: Wuerfel[1][0][12]:=pi;
Beide Schreibweisen sind möglich. Will man ein Array als vorgelegte Variable unter CONST definieren so fasst man einen Indexbereich in klammern () zusammen und trennt Elemente mit Kommas, mehrdimensionale Arrays werden von vorne nach hinten definiert:
Const Tic-Tac-Toe = Array [1..3,'A'..'C'] of Byte =((0,0,0),(1,1,1),(0,1,0));
Das Element [1,'C'] hätte so den Wert 0. Es ist hier farblich hervorgehoben. Es werden also zuerst die Elemente 1..3 der Zeile 'A' gesetzt, dann dasselbe für 'B' und 'C'. In anderen Worten: Die Dimensionen werden von rechts nach links barbeitet.
Man kann dies umgehen indem man in der Deklaration folgendes schreibt
Procedure MachWas(var par: array of xy);
Hier fehlt die Angabe der Dimension, also Anzahl der Elemente ganz. In der Funktion wird par als ein Array mit der Untergrenze 0 und einer variablen Obergrenze angesehen. Die Funktion kann über zwei Funktionen die Anzahl der Elemente und die Größe ermitteln:
for I:=0 to high(par) do par[i]:=...
Eine Anwendung ist hier gezeigt, es handelt sich um den Quicksort Algorithmus, der durch die Verwendung von Prozedurtypen und offenen Arrays so angepasst wurde, das er generell ist:
type
Element = record
name: string;
Gehalt: Double;
Abteilung: string [3];
end;
{Vergleichsfunktion}
Comparefunc = function (var A,B: Element): Boolean;
{ Liefert True wenn a<b, sonst false}
function Vergleich(var A,B: Element): Boolean; far;
function Int2Str(Zahl: Integer ): string;
var Temp: string;
begin
Str(Zahl:5,Temp);
Int2Str:=Temp;
end;
begin
Vergleich:=A.Abteilung+Int2Str(Trunc(A.Gehalt))>B.Abteilung+Int2Str(Trunc(B.Gehalt));
end;
{Klassische Quicksort Implementierung}
procedure Quicksort(Compare: Comparefunc; var Keys: array of Element);
procedure Sort(L, R: Integer);
var
I, J: Word;
X, Y: Element;
begin
I:= L; J:= R; X:= Keys[(L+R) div 2];
repeat
while Compare(Keys[I],X) do Inc(I);
while Compare(X,Keys[J]) do Dec(J);
if I <= J then
begin
Y:= Keys[I]; Keys[I]:= Keys[J]; Keys[J]:= Y;
Inc(I); Dec(J);
end;
until I > J;
if L < J then Sort(L, J);
if I < R then Sort(I, R);
end;
begin
Sort(0,High(Keys));
end;
{Hauptpogramm}
var Abteilungen: array [1..100] of Element;
I : Integer;
begin
Randomize;
for I:=1 to 100 do
with Abteilungen[I] do
begin
name:=Chr(65+Random(26))+'XYZName';
Gehalt:=Random(10000);
Abteilung:=Chr(65+Random(26))+'BC';
end;
Quicksort(Vergleich,Abteilungen);
for I:=1 to 100 do
with Abteilungen[I] do WriteLn(Abteilung,' ',Gehalt:5:0,' ',name);
end.
Der Vorteil dieser Vorgehensweise ist die:
In einer Funktion muss man, wenn man etwas konkretes mit den untypisierten Variablen machen will sie "casten". Daher mal hier ein Einschub für das in Pascal selten gebrauchte Casten unterhalb dieses Absatzes. Man tut dann im Block so als wäre die Variable vom gewünschten Typ :
function Gethighest(Var par; n : integer): byte;;
type bytearray array [0..maxint] of byte;
var temp : Byte;
i : integer;
begin
temp:=0;
for i:=0 to n-1 do
if bytearay(par)[i]>temp then temp:=bytearay(par)[i];
gethighest:=temp;
end;
Hier ermittelt die Funktion das Byte in dem übergebenen Parameter mit dem höchsten Wert. Dazu
wird zweimal gecastet. Zum einen wird zuerst mal so getan als wäre der Parameter ein Array of Byte
beliebiger Größe (Maxint ist die größte Zahl die ein Ganzzahlwert annehmen kann). Danach wird ein
Eintrag gemerkt und der Variable temp zugewiesen. Bitte beachten Sie: Damit unterlaufen sie
komplett die Typüberprüfung des Compilers und sind auf dem Niveau von C angelangt. Man kann diese
Funktion intelligent aufrufen indem man ihr ein Byte oder Char Array (String) übergibt, man kann
aber auch unsinniges machen:
a:=GetHighest(3.14159);
Was da rauskommt hat keinerlei Sinn, denn Flieskommazahlen bestehen nicht aus einem Array von Byte Werten.
Variable:=Casttyp(Variable);
z.B:
var i : integer;
begin
i:=Integer('A'); {A ist ein char Wert!}
end.
Diese Zeile weist der Variable i den Wert 65 zu (ASCII Wert von 'A'). Es wird dabei der Char
Wert in einen Integer Wert gecastet. Man könnte auch sagen: Es wird eine Funktion aufgerufen die
einen umgewandelten Integer Wert zurückgibt. Man braucht das Casten insbesondere, wenn man auf
Datenträgern Werte wie Boolean oder Aufzählungstypen speichern will und diese mit writeln / readln
schreibt und liesst. Dann konvertiert man in Integer beim Schreiben und in den gewünschten Typ beim
Lesen.:
var boolvar : Boolean;
temp : Byte;
begin
Writeln(datei,Byte(Boolvar));
readln(datei,temp);
boolvar:=boolean(Temp);
end;
Die trigonometrischen Funktionen sin(, cos( und arctan( arbeiten nur mit Bogenmaß (Periode 2 Pi), will man dagegen im Winkelmaß arbeiten so muß man umrechnen - das erledigt eine eigene Funktion besser als das 10 mal im Quelltext zu tun.
function sinus(winkel : extended): extended;
const umrechungsfaktor 360 / (2*Pi);
begin
sinus:=sin(winkel/Umrechnungsfaktor);
end;
Oft benötigt man auch eine Funktion die bei einer Eingabe Leezeichen entfernt, die vor der eigentlichen Eingabe stehen:
function Trim(eingabe : string): String;
begin
while (length(eingabe)>0) and (eingabe[1]=' ') do
delete(eingabe,1,1);
trim:=eingabe;
end;
Was sie jetzt auch schon machen können ist mit dem Computer zahlreiche Denksportaufgaben
lösen. Hier mal eine Aufgabe aus der ARD Sendung "Kopfball" vom 23.12.2001: "Eine
Bahnhofsuhr mit 7 Segment Anzeige (Wie bei Taschenrechnern) zeigt die Zeit an. Dabei hat sie
je zwei Ziffern für Stunden, Minuten und Sekunden, die erste Stundenziffer leuchtet aber erst
ab 10 Uhr (die
führende Null wird nicht dargestellt). Bei welcher Uhrzeit leuchten die meisten Segmente?
Klar man kann nachdenken oder den computer einfach mal von 0:00:00 bis 23:59:59 alle Uhrzeiten durchprobieren lassen. Das wäre doch eine nette kleine Aufgabe. Herauskommen sollte dann so was. Falls sie eine andere Lösung finden: Die korrekte Uhrzeit ist 20:08:08.
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.
Die 2014 erschienene zweite Auflage wurde aktualisiert und leicht erweitert. Die umfangreichste Änderung ist ein 60 Seiten starkes Kapitel über Seymour Cray und die von ihm entworfenen Supercomputer. Bedingt durch Preissenkungen bei Neuauflagen ist es mit 19,90 Euro trotz gestiegenem Umfang um 5 Euro billiger als die erste Auflage. Es ist auch als e-Book für 10,99 Euro erschienen.
Mehr über das Buch auf dieser eigenen Seite.
Hier geht's zur Gesamtübersicht meiner Bücher mit direkten Links zum BOD-Buchshop. Die Bücher sind aber auch direkt im Buchhandel bestellbar (da ich über sehr spezielle Themen schreibe, wird man sie wohl kaum in der Auslage finden) und sie sind natürlich in den gängigen Online-Plattformen wie Amazon, Libri, Buecher.de erhältlich.
Sitemap | Kontakt | Impressum / Datenschutz | Neues | Hier werben / advertisment here | Buchshop | Bücher vom Autor |