Home | Computer | Pascal Kurs | Site Map |
TYPE
Personaltyp = record String [20];
Gehalt : Integer;
Angestellt: Boolean;
end;
Man erkennt hier schon etwas bekanntes: Ein Record setzt sich aus eine Typ und Variablendefinition zusammen. In der ersten Zeile mit dem Schlüsselwort record wird der Typname definiert (hier: personaltyp). Es folgen dann die einzelnen Felder des Records, die genauso wie Variablen festgelegt werden : Name: Typ; Abgeschlossen wird die Deklaration mit dem Schlüsselwort end;. Man nennt das auch einen benutzerdefinierten oder zusammengesetzten Datentyp. Deklariert wird der Record in der Typendeklaration, denn er ist ja ein neuer Datentyp
Nun kann dieser neue Typ Personaltyp für eigene Variablen verwendet werden. Dies geschieht indem man in der var Sektion eine neue Variable dieses Types anlegt:
var
mitarbeiter : Personaltyp
personal : array [1..100] of Personaltyp;
Hier wird gleich ein ganzes Array (eine Firma hat ja meistens mehr als einen Mitarbeiter...) aus diesem Typ definiert.
mitarbeiter.name'Lieschen Müller'
personal[11].gehalt:=3500;
Sind Records Bestandteil von Records, was vor allem bei Objekten in Delphi oft vorkommt, so wird das ganze länglich und auch unübersichtlich. Hier gibt es die WITH Anweisung die einen Record öffnet:
WITH personal[i] DO
BEGIN
gehalt:=1000;
Name:='Bernd Leitenberger';
Angestellt:=true;
END;
Die WITH Anweisung öffnet einen Record. Wie bei FOR umfasst sie nur die nächste Anweisung, man muss also in der Regel einen Block mit begin..end einfügen. Man kann nun auf die einzelnen Felder zugreifen, ohne den Record anzugeben. In C/C++ und Java wäre ich auch dafür dankbar, denn erspart Schreibarbeit und macht das Programm übersichtlicher. Doch wichtiger sind Operationen die man mit ganzen Records machen kann. Wenn Sie das obige Beispiel sich ansehen so ist klar, das in diesem Record zusammengehörende Werte sind. Jeder Angestellte hat einen Namen, ein Gehalt und ist fest angestellt oder nur freier Mitarbeiter. Verlässt nun ein Mitarbeiter ihre Firm so müssten sie bei 3 Arrays mit den einzelnen Feldern jeweils eines löschen, also 3 mal dieselbe Operation machen.
Records dagegen kann man auch als ganze Einheiten auffassen, d.h. man kann alle Felder die in einem Record enthalten sind zusammen löschen, zuweisen, kopieren. So ist der Zugriff wesentlich vereinfacht. Wenn Sie mit einem Record arbeiten, so arbeiten sie einfach mit dem Recordnamen anstatt den Feldnamen:
VAR neuer_mitarbeiter: Personaltyp;
....
personal[i]:=neuer_mitarbeiter;
...
Hier wird ein neuer Mitarbeiter aufgenommen der einfach durch eine einfache Zuweisung vorgenommen wird. Will man die Personal Liste sortieren so würde man das so machen:
for i:=1 to 99 do
for j:=i+1 to 100 do
if personal[i].name>personal[j].name then
begin
neuer_mitarbeiter:=personal[j];
personal[j]:=personal[i];
personal[i]:=neuer_mitarbeiter;
end;
Bei diesem einfachen Sortieralgorithmus wird neuer_mitarbeiter als Zwischenspeicher benutzt um die Mitarbeiter jeweils auszutauschen. Noch wichtiger sind Records bei Dateien, doch dazu später mehr.
Zeiger oder Pointer sind Variablen die als Wert eine Speicheradresse haben. Ihre Größe hängt
daher vom Betriebssystem ab, unter DOS/Windows sind es immer 4 Byte. Ein Zeiger zeigt (daher
die Name) auf eine Variable:
var S : string;
P : ^string;
begin
S:='Hallo Welt';
P^:=S;
WriteLn(P^);
end.
In diesem Fall zeigt P auf S. Der Inhalt von P ist die Adresse des ersten
Bytes von S. Man unterscheidet von nun an zwei Dinge: Der Inhalt des Zeigers ist die
Adresse eines Objektes. Ein Objekt ist eine Variable mit einem Inhalt. Der springende Punkt
ist das man nun zwei Möglichkeiten hat:
procedure Veraednere(VAR Wert)
um einen Wert zu ändern so übergeben Sie einen Zeiger und arbeiten mit einem Zeiger - Genauso wie in C. Nur muss dort der Programmierer selbst immer aufpassen ob er Änderungen am Zeiger macht oder an der Variable auf die der Zeiger zeigt.
Ein Zeiger wird so angelegt:
New(Zeiger);
Zeiger ist eine Zeigervariable Bsp.:
Type Zeile string[80];
var zeiger Zeile;
begin
New(Zeiger);
Zeiger^:='Hallo';
writeln(zeiger^);
dispose(zeiger);
end.
New macht folgendes: Es erkennt den Zeigertyp (in diesem Fall Zeiger auf 80 Zeichen), holt sich vom Speicher soviel Bytes wie der Typ benötigt (hier also 80 Bytes) und weist dem Zeiger die Adresse zu auf diese 80 Bytes. Danach (und erst jetzt) zeigt der Zeiger auf einen Bereich denn man mit Daten füllen kann. Hier wird also der String "Hello" dort gespeichert und dann ausgegeben. Zuletzt ruft man die zweite wichtige Prozedur auf: Dispose - sie gibt den Speicher wieder frei, danach kann man nicht mehr auf den Zeiger zugreifen, da er nicht mehr auf den Speicher zeigt.
Also es ist Prinzipiell ganz einfach mit Zeigern:
Eine Textdatei wird zeilenweise gelesen. Dies geschieht mit Read bzw. Readln und Write bzw. Writeln. Im Prinzip funktionieren Textdateien wie die Eingaben über die Tastatur. Der häufigste Fall ist das Einlesen von Strings, aber auch Fliesskommazahlen oder Integer Werte können so eingelesen werden, dann wird automatisch konvertiert, sofern möglich.
Es gibt 5 Dinge bei der Bearbeitung einer Datei zu tun:
program datei_t;
var Datei : Text; {Dateivariable deklariert}
I : integer;
begin
assign(datei,'Test.txt'); {Datei mit "Test.txt" verknüpfen}
rewrite(datei); {Datei zum schreiben öffnen}
for i:=1 to 10 do writeln(datei,i); {Werte von 1 bis 10 in Datei schreiben}
close(datei); {Datei schließen - erst jetzt wird auf die Disk geschrieben!}
reset(datei); {Datei nun zum Lesen öffnen - die Verknüpfung ist nicht nochmals nötig!}
while not eof(datei) do {solange wie das Dateiende (EOF = End of File) nicht erreicht ist}
readln(datei,i); {Wert einlesen}
Close(datei);
erase(datei); {war nur ein Test die Datei kann nun gelöscht werden}
end;
In diesem Beispiel sieht man die auch die elementaren Dateifunktionen:
Deklariert werden untypisierte Dateien als FILE. Das OF Typname entfällt natürlich weil sie keinem Typ gehorchen (Bitte beachten Sie: Ein FILE OF BYTE ist eine typisierte Datei auf die Sie wahlfrei zugreifen können, FILE dagegen eine untypisierte Datei).
Beim Öffnen mit Reset oder Rewrite ist ein zweiter Parameter anzugeben der angibt wieviel Bytes ein Record umfasst, die kleinste Einheit auf die zugegriffen wird. Üblicherweise will man Byteweise zugreifen und wird hier z.B. Angeben Reset(datei,1). Lässt man den Parameter weg so wird 128 angenommen, was selten das ist, was man wünscht.
Lesen und schreiben tut man mit den Prozeduren Blockwrite(dateivariable,VAR Puffer,Puffergröße,VAR gelesene_Bytes) und Blockwrite(dateivariable,VAR Puffer,geschriebene_Bytes).
Beispiel: Eine Routine die eine Datei kopiert:
procedure Kopier(Datei1,Datei2 : String);
Type Puffer Array [1..60000] of Byte;
VAR File1,file2 : File;
Pufzeiger : ^Puffer;
anzahl_bytes : longint;
begin
Assign(file1,datei1);
Assign(file2,datei2);
{$I-}
reset(file1,1);
if ioresult>0 then exit;
{$I+}
Rewrite(file2,1);
New(Pufzeiger);
while not eof(file1) do
begin
blockread(file1,pufzeiger^,sizeof(pufzeiger^),anzahl_bytes);
blockwrite(file1,pufzeiger^,anzahl_bytes);
end;
dispose(pufzeiger);
close(file1);
close(file2);
end;
Diese Beispiel zeigt auch wie man eine Zeigervariable benutzt: Es wäre reine Verschwendung 60 Kilobytes für einen Puffer zu reservieren, der nur kurz innerhalb der Prozedur benötigt wird. Wenn Sie einmal das Lesen einer Textdatei und einer untypisierten Datei vergleichen, so werden sie sehen, das untypisierte Dateien erheblich schneller sind. Das hat zwei Gründe. Zum einen muss der Inhalt nicht interpretiert werden, d.h. es wird nicht nach Zeilenende gesucht und dann versucht die Zeile in Variablen zu zerlegen und diese zuzuweisen. Zum zweiten arbeiten Textdateien mit einem sehr kleinen Standardpuffer von 128 Bytes, das ist kleiner als die Clustergröße mit der ihre Festplatte arbeitet (typische Werte hier 4-16 K). Zumindest letzteres kann man aber beseitigen indem man einen Textbuffer anbietet:
var buffer = Array [1..8192] of Byte {8 K Buffer}
...
Assign(Datei,Dateiname);
Settextbuf(Datei,buffer);
Mit SetTextbuf (Dateivariable,Array,Arraygröße) kann man einen Buffer zuordnen, der dann benutzt wird. Es sind zwei Dinge zu beachten: Das Zuordnen muss vor dem ersten Zugriff geschehen - Am besten nach Assign, oder direkt nach Rewrite,Append oder Reset, aber vor dem ersten Read/Write. Zum zweiten muss der Puffer über die Lebensdauer einer Datei existieren. Ein beliebter Fehler ist es eine Datei in Prozedur A zu öffnen und in Prozedur B zu bearbeiten. Wenn der Puffer hier in A deklariert ist, so liegt er auf dem Stack und wird bei Prozedur B mit lokalen Variablen überschrieben!
Es gibt im Prinzip zwei Compiler Switchsorten:
lokale: Können in einer Quelltextdatei mehrmals geändert werden. Der $I Switch für die Prüfung von I/O Results ist so einer. Mann wird ihn an kritischen Stellen nutzen und an anderen ausschalten. Auch bedingte Compilierung (Teile des Quelltexts compilieren und andere nicht je nach Einstellungen) gehören dazu.
Globale: Wirken auf das ganze Programm. z.B. Das Einschalten der 80286 Befehle oder die Verwendung eines nummerischen Coprozessors. Diese können nur einmal im Programm gesetzt werden.
$R: Bereichsprüfung
Der Compiler bricht ab wenn man einen Wertebereich verlässt. Es gibt hier vor allem zwei Fälle wo dies zum Tragen kommt:
Ähnlich wie die Bereichsprüfung, jedoch bei einfachen Variablen: Wenn Sie zu einer Smallint Variable (Wertebereich -127... 128) die den Wert 120 hat, 10 addieren passt das Ergebnis nicht mehr in 1 Byte und es ergibt sich nicht der Wert 130 sondern -126, das ist wohl nicht das was sie haben wollten. $Q macht Sie darauf aufmerksam. Als guter Programmierer verwenden Sie aber doch immer etwas größere Variablen oder Teilbereichstypen oder?
$V: Strenge VAR Strings
Wenn Sie Strings an eine Prozedur als VAR Parameter übergeben müssen nach Standard Pascal der formale Parameter und der Aktuelle übereinstimmen. Bei einem Funktionskopf procedure x(var y : string[10]) wäre es nicht erlaubt, diesen mit einem String[20] oder String [11] aufzurufen. Dieser Switch erlaubt es das auszuschalten. Wenn sie mit TP 7.0 und höher arbeiten brauchen sie ihn gar nicht, denn es gibt hier die leistungsfähigeren offenen Strings.
$S: Stack Überprüfung
Diesen Schalter braucht man eigentlich immer. Der Hintergrund: Es gibt ein Stacksegement in dem bei Aufruf einer Funktion lokale Variablen, Parameter etc. gespeichert werden. Hat man das zu klein eingestellt so verabschiedet sich das Programm recht endgültig zumeist auch noch der Debugger und Computer dazu. Das tritt leider erst auf, wenn das Programm mal an eine Stelle kommt wo viele lokale Variable vorliegen. Mit Stacküberprüfung bekommt man noch eine schöne Fehlermeldung und kann dann den Wert für das Stacksegment vergrößern.
$B: Boolsche Ausdrücke:
Die schon erwähnte Auswertung nach dem Kurzschlussprinzip. Bestimmt ob ein Ausdruck der Form (expr1 or expr2) noch ausgewertet wird wenn expr1 schon wahr ist und man expr2 somit nicht mehr braucht. Manche Sachen Funktionieren nur mit $B- andere nur mit $B+, was hängt von ihrem Programmierstill ab.
$I: IO Prüfung ein oder aus
Wird typischerweise bei einem Reset / Rewrite eingesetzt. Um festzustellen ob eine Datei geöffnet werden kann oder nicht
Machen Sie sich mit dem Compiler Switches vertraut. Sie sind ihre Freunde. Anders als in C können sie auf Überlauf prüfen lassen oder ob eine Variable ihren Definitionsbereich verlassen hat. So was ist beim Debuggen sehr nützlich. Erst wenn sie das Programm fehlerfrei haben schalten sie die Überprüfungen aus.
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 |