.PL72
.MT1
.MB3
.FM1
.FO
.HE TURBO-Pascal Seite #
.PN38
.PO8
10. Feldtypen (ARRAY)
Ein Feld (ARRAY) ist ein strukturierter Typ, der aus einer festen
Anzahl von Komponenten besteht. Die Komponenten sind alle vom
gleichen Typ. Diesen bezeichnet man als Komponententyp oder Ba-
sistyp. Jede dieser Komponenten kann man exakt durch Indizierung
des Feldes erreichen. Indizes sind INTEGER-Ausdruecke, die in
eckigen Klammern geschrieben, an den Bezeichner des Feldes ange-
haengt werden. Ihr Typ heisst Indextyp.
10.1 Feld-Definition
Die Definition eines Feldes besteht aus dem reservierten Wort
array, dem ein in eckigen Klammern eingeschlossener Indextyp
folgt. Nach diesem steht das reservierte Wort of und ein Kompo-
nententyp.
Beipiele:
type
Day = (Mon,Die,Mit,Don,Fre,Sam,Son);
Var
WorkHour : array[1..8] of Integer;
Week : array[1..52] of Day;
type
Players = (Player1,Player2,Player3,Player4);
Hand = (One,Two,Pair,TwoPair,Three,Straight,Flush,
FullHouse,Four,StraightFlush,RSF);
LegalBid = 1..200;
Bid = array[Players];
Var
Player : array[Players] of Hand;
Pot : Bid;
Die Zuweisung zu einer Feld-Komponente erfolgt durch Angabe eines
in eckigen Klammern eingeschlossenen Indexes hinter dem Variab-
lenbezeichner.
Beispiele:
Player[Player3] := FullHouse;
Pot[Player3] := 100;
Player[Player4] := Flush;
Pot[Player4] := 50;
Es ist erlaubt, einer Variablen x den Wert einer anderen
Variablen Y zuzuweisen, wenn beide den gleichen Typ haben. Analog
ist es moeglich ganze Felder zu kopieren:
Index1 := Index2.
Die Compiler-Direktive R steuert auch die Erzeugung eines Codes,
der zur Laufzeit des Programmes die Index-Ausdruecke prueft, ob
sie innerhalb des erlaubten Bereiches liegen. Standard ist dabei
{$R-}, d.h. es muss im Programm {$R+} gesetzt werden, wenn die
Index-Ausdruecke geprueft werden sollen.
.pa
10.2 Mehrdimensionale Felder
Der Komponententyp eines Feldes kann ein jeder Datentyp sein,
d.h. der Komponententyp kann auch ein Feld sein. Eine solche
Konstruktion heisst mehrdimensionales Feld.
Beispiele:
type
card = (Two,Three,Four,Five,Six,Seven,Eight,Nine,Ten,
Knight,Queen,King,Ace);
Suit = (Hearts,Spade,Clubs,Diamonds);
AllCards = array[Suit] of array[1..13] of Card;
var
Deck : AllCards;
Ein mehrdimensionales Feld kann auch durch mehrdimensionale
Indices definiert werden:
type
AlCards = array[Sui,1..13] of Card;
Aus diesem Grunde kann man auch folgende kuerzere Schreibweise
fuer die Auswahl eines Feldes anwenden:
Deck[Hearts,10] equivalent mit Deck[Hearts][10]
Es ist natuerlich auch moeglich mehrdimensionale Felder in Termen
vorher definierter Feldtypen zu definieren.
Beispiele:
type
Pupils = string[10];
Class = array[1..30] of Pupils;
Scool = array[1..100] of Class;
var
J,P,Vacant : Integer;
ClassA,ClassB : Class;
NewTownScool : Scool;
Mit diesen Definitionen gelten folgende Zuweisungen:
ClassA := 'Peter';
NewTownScool[5][21] := 'Peter Brown';
NewTownScool[8,J] := NewTownScool[7,J];
ClassA[Vacant] := ClassB[P];
10.3 Zeichenfelder (Caracter Arrays)
Zeichenfelder sind Felder mit einem Index und Komponenten vom
Standard-Skalar-Typ Char. Zeichenfelder koennen auch als String
mit fester Laenge aufgefasst werden.
In TURBO-Pascal duerfen Zeichenfelder auch in STRING-Ausdruecken
auftreten. In diesen Faellen werden jeweils in einen String von
der Laenge des Zeichenfeldes umgewandelt. Damit koennen Zeichen-
felder in gleicher Weise wie String miteinander verglichen und
manipuliert werden. Auch Stringkonstanten duerfen Zeichenfeldern
zugewiesen werden, wenn sie die gleiche Laenge haben. STRING-
Variable und -Werte, die aus STRING-Ausdruecken berechnet werden,
koennen Zeichenfeldern nicht zugewiesen werden.
10.4 Standard-Felder
TURBO-Pascal stellt zwei Standard-Felder vom Typ Byte zur Verfue-
gung: MEM und PORT. Mit ihnen erhaelt man den Zugriff zum Spei-
cher und zu den Datenports. Ihre Besprechung erfolgt in Anhang A
und B.
11. Datensatztypen
Ein Datensatz ist eine Struktur, die aus einer festen Anzahl von
Komponenten, den Datenfeldern, besteht. Die einzelnen Datenfelder
koennen von unterschiedlichem Typ sein und jedes Datenfeld hat
einen eigenen Datenfeldbezeichner, der dem Zugriff zu diesem
Datenfeld dient.
11.1 Datensatz-Definition
Die Definition eines Datensatztyps besteht aus dem reservierten
Wort record, dem eine Datenfeldliste folgt. Diese Liste wird
durch das reservierte Wort end abgeschlossen. Sie besteht aus
Datensatzabschnitten, die voneinander durch Semikolon getrennt
sind. Jeder Datensatzabschnitt besteht aus einem oder mehreren
Datenfeldbezeichnern, die durch Komma voneinander getrennt sind.
Der letzte wird durch einen Doppelpunkt abgeschlossen. Diesem
folgt ein Typbezeichner. Jeder Datensatzabschnitt spezifiziert
demnach den Typ und die Bezeichner fuer einen oder mehrere Daten-
felder.
Beispiele:
type
Date = record
Day : 1..31;
Month : (Jan,Feb,Mrz,Apr,Mai,Jun,Jul,Aug,
Sep,Okt,Nov,Dez);
Year : 1900..1999;
end;
var
Birth : Date;
WorkDay : array[1..5] of date;
In diesem Beispiel sind Day, Month und Year Datenfeldbezeichner.
Ein Datenfeldbezeichner muss nur eindeutig in dem Datensatz
selbst sein, indem er definiert wurde. Den Zugriff zu einem
Datenfeld erhaelt man durch den Datenfeldbezeichner, dem man,
getrennt durch einen Punkt, den Variablenbezeichner fuer diesen
Datensatz voranstellt.
Beispiele:
Birth.Month := Jun;
Birth.Year := 1950;
WorkDay[Current] := WorkDay[Current-1];
Man beachte, dass wie bei den Feltypen auch ganze Datensaetze
einander zugewiesen werden koennen, wenn sie vom gleichen Typ
sind.
Da der Typ der Datensatzkomponenten nicht eingeschraenkt ist,
kann er selbstverstaendlich auch ein Datensatztyp sein. Damit ist
es moeglich, einen Datensatz von Datensaetzen zu bilden:
type
Name = record
FamilyName : string[32];
ChristianName : array[1..3] of string[16];
end;
Rate = record
NormalRate,OverTime,NightTime,Weekend:Integer;
end;
Date = record
Day : 1..31;
Month : (Jan,Feb,Mrz,Apr,Mai,Jun,Jul,Aug,
Sep,Okt,Nov,Dez);
Year : 1900..1999;
end;
Person = record
Id : Name;
Time : Date;
end;
Wages = record
Individual : Person;
Cost : Rate;
end;
var
Salary,Fee : Wages;
Mit diesen Definitionen sind folgende Zuweisungen erlaubt:
Salary := Fee;
Salary.Cost.OverTime := 950;
Salary.Individual.Time := Fee.Individual.Time;
Salary.Individual.Id.FamilyName := 'Smith';
11.2 WITH-Anweisung
Die Verwendung von Datensaetzen in der obigen Weise ergibt meis-
tens ziemlich weitschweifige Anweisungen. Die Schreibweise der
Ergibtanweisungen wuerde einfacher sein, wenn die Datensatzfelder
einfache Variablen waeren. Genau dies ermoeglicht die WITH-An-
weisung: Sie "eroeffnet" einen Datensatz so, dass die Datenfeld-
bezeichner wie einfache Variablenbezeichner verwendet werden
koennen.
Eine WITH-Anweisung besteht aus dem reservierten Wort with, dem
eine Liste von Datensatzvariablen folgt, die durch Komma vonein-
ander getrennt sind. Anschliessend folgt das reservierte Wort do
und eine Anweisung.
In einer WITH-Anweisung wird ein Datenfeld nur durch seinen
Datenfeldbezeichner gekennzeichnet, d.h. ohne Datensatzvariablen-
bezeichner.
with Date do
begin
Day := 23;
Month := Feb;
Year := 1982;
end;
Datensaetze koennen in einer WITH-Anweisung geschachtelt werden,
d.h. Datensaetze von Datensaetzen koennen wie folgt eroeffnet
werden:
with Salary do with Individual do with Id do ...
oder kuerzer:
with Salary,Individual,Id do
begin
FamilyName := 'Smith';
ChristianName := 'Jones';
end;
Die maximale Tiefe dieser Schachtelung der WITH-Folgen, d.h. die
maximale Anzahl der Datensaetze, die man in einem Block zur
gleichen Zeit eroeffnen kann, haengt von der Implementierung ab.
Eine ausfuehrliche Besprechung erfolgt im Anhang A und B.
.pa
11.3 Definition von Datensatz-Varianten.
Die Syntax eines Datensatztypes erlaubt auch die Definition von
Datensatzteil-Varianten, d.h. von alternativen Datensatzstruktu-
ren, die aus Datensatzteilen bestehen, deren Datenfeldanzahl und
Datenfeldtypen unterschiedlich sind und deren Struktur jeweils
vom Wert eines Kennzeichnungsfeldes abhaengen.
Ein Varianten-Datensatzteil besteht aus einem Kennzeichnungsfeld
eines vorher definierten Typs, dem Marken folgen, die den moeg-
lichen Werten des Kennzeichnungsfeldes entsprechen. Jede Marke
fuehrt eine Datenfeldliste an, die den Typ der dieser Marke
zugeordneten Datensatzteil-Variante definiert.
Als Beispiel gelte obige Typdefinition fuer Name und Date, sowie
type Origin = (Citizen,Alien);
Dann ist es mit der folgenden Datensatztyp-Definition moeglich,
fuer das Datenfeld CitizenChip zwei verschiedene Strukturen zu
definieren, die nur von seinem Wert: Citizen oder Alien abhaen-
gen:
type
Name = record
FamilyName : string[32];
ChristianNames : array[1..3] of strings[16];
HourRates : array[1..4] of Integer;
end;
Person = record
PersonName : Name;
BirthDate : Date;
case CitizenShip : Origin of
Citizen: (BirthPlace :Name);
Alien : (CountryOfOrigin : Name;
DateOfEntry : Date;
PermittedUntil : Date;
PortOfEntry : Name);
end;
Bei dieser Definition von Datensatzvarianten ist das Kennzeich-
nungsfeld ein explizites Datenfeld, das man wie jedes andere
Datenfeld auswaehlen und mit Werten versehen kann. Es sind des-
halb auch die folgenden Anweisungen exakt gueltig:
var Passenger : Person;
Passenger.CitizenShip := Citizen;
with Passenger,Person,Name do
if CitizenShip = Alien then writeln(FamilyName);
Der feste Teil eines Datensatzes, d.h. der Teil, der gleiche
Datenfelder enthaelt, muss stets vor dem variablen Teil liegen.
Im obigen Beispiel sind PersonName und BirthDate die festen
Felder. Ein Datensatz darf nur einen variablen Teil haben. Im
variablen Teil muessen die Klammern geschrieben werden, auch wenn
sie nichts enthalten.
Die Nutzung eines Kennzeichnungsfeldes liegt in der Verantwortung
des Programmierers und nicht bei TURBO-Pascal. Aus diesem Grunde
kann man sich auf das Feld DateOfEntry im Typ Person auch bezie-
hen, wenn das Kennzeichnungsfeld CitizenChip nicht den Wert Alien
hat. Tatsaechlich kann man das Kennzeichnungsfeld ueberall weg-
lassen, indem man den Typbezeichner streicht. Solche Datensatzde-
finitionen sind bekannt als freie Vereinigungen (free unions). Im
Gegensatz dazu heissen diejenigen mit Kennzeichnungsfeld gekenn-
zeichnete Vereinigungen (discriminated unions). Die Verwendung
freier Vereinigungen sind selten und sollten nur von erfahrenen
Programmierern praktiziert werden.
.pa
12. Mengentypen
Eine Menge ist eine Sammlung verwandter Objekte, die man sich als
eine Gesamtheit vorstellen kann. Jedes Objekt einer solchen Menge
heisst Mitglied oder Element der Menge. Beispiele fuer Mengen
sind:
1) Alle ganzen Zahlen von 0 bis 100.
2) Alle Buchstaben des Alphabets.
3) Alle Konstanten des Alphabets.
Zwei Mengen sind dann und nur dann gleich, wenn ihre Elemente die
gleichen sind. Es gibt in dieser Definition keinen Ordnungsbe-
griff, sodass folgende Mengen gleich sind:
[1,3,5] [5,3,1] [3,5,1].
Wenn alle Elemente einer Menge auch Elemente einer anderen Menge
sind, sagt man, dass diese Menge in der anderen Menge enthalten
ist. Sie wird auch als Teilmenge der anderen Menge bezeichnet. Im
obigen Beispiel ist 3) in 2) enthalten.
Es gibt drei Operationen, die den Zahlenoperationen entlehnt sind
und auf Mengen angewandt werden koennen: die Vereinigung (+), der
Durchschnitt (*) und das relative Komplement (-):
Die Vereinigung (oder Summe) zweier Mengen A und B,
geschrieben A+B, ist die Menge aller Elemente, die entweder
in A oder in B enthalten sind. Die Vereinigung von [1,3,5,7]
und [2,3,4] ist [1,2,3,4,5,7].
Der Durchschnitt (oder Produkt) zweier Mengen A und B,
geschrieben A*B, ist die Menge aller Elemente, die sowohl in
A als auch in B enthalten sind. Der Druchschnitt von
[1,3,4,5,7] und [2,3,4] ist [3,4].
Das relative Komplement (oder die Differenz) von B
bezueglich A, geschrieben A-B, ist die Menge aller Elemente,
die in A aber nicht in B enthalten sind. Die Differenz von
[1,3,4,5,7] und [2,3,4] ist [1,5,7].
12.1 Mengentyp-Definition
Obgleich es in der Mathematik keine Einschraenkungen fuer die
Elemente einer Menge gibt, gestattet Pascal nur eine einge-
schraenkte Form der Definition von Mengen:
Die Elemente einer Menge muessen alle vom gleichen Typ sein, dem
Basistyp. Der Basistyp muss ein einfacher Typ sein, d.h. ein
beliebiger Skalartyp ausser REAL. Die Definition eines Mengentyp
besteht aus einem Mengentypbezeichner, dem ein Gleichheitszeichen
und die reservierten Worte set of und ein einfacher Typ folgen.
Beispiele:
DaysOfMonth = set of 0..31;
WorkWeek = set of Mon..Fre;
Letter = set of 'A'..'Z';
Additiv Colors = set of [Red,Green,Blue];
Characters = set of Char;
In TURBO-Pascal betraegt die maximale Anzahl von Elementen einer
Menge 256 und die Ordnungswerte des Basistyp muessen im Be-
reich 0..255 liegen.
.pa
12.2 Mengenausdruecke
Mengenwerte koennen aus anderen Mengenwerten durch Mengenaus-
druecke berechnet werden. Mengenausdruecke bestehen aus:
Mengenkonstruktionen,
Mengenoperatoren,
Mengenkonstanten und
Mengenvariablen.
12.2.1 Mengenkonstruktionen
Eine Mengenkonstruktion besteht aus einer oder mehreren Elemen-
tenspezifikationen, die durch Komma voneinander getrennt und in
eckige Klammern eingeschlossen sind. Eine Elementenspezifikation
ist ein Ausdruck vom gleichen Typ wie der Basistyp der Menge. Sie
kann auch ein Bereich sein, der durch zwei solcher Ausdruecke
dargestellt wird, getrennt durch zwei aufeinanderfolgende Punkte.
Beispiele:
['T','U','R','B','O']
['X','Y']
[X..Y]
[1..5]
['A'..'Z','a'..'z','0'..'9']
[1,3..10,12]
[]
Das letzte Beispiel stellt die leere Menge dar. Da sie keinen
Ausdruck enthaelt, der ihren Basistyp festlegt, ist sie mit allen
Mengentypen kompatibel. Die Menge [1..5] ist der Menge
[1,2,3,4,5] equivalent. Wenn X>Y, dann bezeichnet [X..Y] die
leere Menge.
12.2.2 Mengenoperationen
Die Mengenoperationen werden entsprechend ihrer Rangfolge in
folgende drei Klassen eingeteilt:
1) * Mengendurchschnitt.
2) + Mengenvereinigung,
- Mengendifferenz.
3) = Test auf Gleichheit,
<> Test auf Ungleichheit,
>= Wahr, wenn der zweite Operand im ersten enthalten
ist,
<= Wahr, wenn der erste Operand im zweiten enthalten
ist,
in Test auf Mitgliedschaft in einer Menge. Der zweite
Operand ist ein Mengentyp und der erste ein Mengen-
ausdruck vom gleichen Typ wie der Basistyp der
Menge. Das Ergebnis ist wahr, wenn der erste Ope-
rand ein Element des zweiten Operanden ist, andern-
falls ist es falsch.
Es gibt keinen Operator fuer ein exaktes Nichtenthaltensein. Aber
man kann dies in der Form A*B = [] programmieren.
.pa
Mengenausdruecke sind oft brauchbar, um komplizierte Tests ein-
facher zu programmieren. Dafuer einige Beispiele:
fuer: (CH='T') or (CH='U') or (CH='R') or (CH='B') or (CH='O')
besser: CH in ['T','U','R','B','O']
fuer: (CH>'0') and (CH<'9')
besser: CH in ['0'..'9']
12.2.3 Mengenzuweisungen
Mengenvariablen wird das Ergebnis von Mengenausdruecken durch das
Ergibtzeichen ':=' zugewiesen.
Beispiele:
type
ASCII = set of 0..127;
var
NoPrint,Print,AllChars : ASCII;
begin
AllChars := [0..127];
NoPrint := [0..31,127];
Print := AllChars - NoPrint;
end;
.pa
13. Typisierte Konstante
Typisierte Konstante sind eine TURBO Spezialitaet. Eine typisier-
te Konstante kann man exakt wie eine Variable vom gleichen Typ
verwenden. Sie koennen deshalb als initialisierte Variable einge-
setzt werden. Denn ihr Wert ist von Anfang an definiert, waehrend
eine Variable solange undefiniert ist, bis ihr ein Wert zugewie-
sen wurde.
Man sollte natuelich darauf achten, das einer typisierten
Konstante keine Werte zugewiesen werden, denn ihr Wert sollte
eben wirklich konstant sein.
Die Verwendung typisierter Konstanten hilft Speicherplatz sparen,
wenn sie haeufig im Programm verwendet werden. Denn sie werden im
Programmcode nur einmal gespeichert, im Gegensatz zu den untypi-
sierten Konstanten, die im Code jedesmal gespeichert werden, wenn
sie im Text vorkommen.
Typisierte Konstanten werden wie untypisierte Konstanten
definiert (siehe 5.2.2), sie enthalten nur zusaetzlich auch ihren
Typ.
Die Definition einer typisierten Konstanten besteht aus dem
Konstantenbezeichner, einem Doppelpunkt, einem Typbezeichner,
einem Gleichheitszeichen und dem wirklichen Konstantenwert.
13.1 Unstrukturierte typisierte Konstante
Eine unstrukturierte typisierte Konstante ist eine Konstante, die
durch einen Skalartyp definiert wird.
Beispiele:
NumbersOfCars : Integer = 1267;
Interest : Real = 12.67;
Heading : string[7] = 'Section';
Xon : Char = ^Q;
Im Gegensatz zu den untypisierten Konstanten kann eine typisierte
Konstante anstelle einer Variablen als Parameter in einer Pro-
zedur oder Funktion verwendet werden. Eine typisierte Konstante
ist tatsaechlich eine Variable mit einem konstanten Wert. Sie
kann deshalb nicht in der Definition anderer Konstanten oder
Typen verwendet werden. Deshalb ist im folgenden Beispiel die
Verwendung der typisierten Konstanten Min und Max nicht erlaubt:
const
Min : integer = 0;
Max : integer = 50;
type
Range : array[Min..Max] of integer; {Falsch !}
13.2 Strukturierte typisierte Konstante
Strukturierte Konstante sind
Feldkonstante,
Datensatzkonstante und
Mengenkonstante.
Sie werden häufig verwendet, um initialisierte Tabellen und Men-
gen fuer Tests, Konvertierungen, Abbildungsfunktionen usw. be-
reitzustellen. Die folgenden Abschnitte definieren jeden Typ im
Einzelnen.
.pa
13.2.1 Feldkonstante
Die Definition einer typisierten Feldkonstanten besteht aus dem
Konstantenbezeichner, einem Doppelpunkt, dem Typbezeichner eines
vorher definierten Feldtyps, dem Gleichheitszeichen und dem kon-
stanten Wert. Letzterer besteht aus einer Liste von Konstanten,
die durch Komma getrennt und in Klammern eingeschlossen sind.
Beispiele:
type
Status = (Activ,Passiv,Wartend);
StringRep = array[Status] of string[7];
const
Stat:StringRep = ('aktiv','passiv','wartend');
Das Beispiel definiert die Feldkonstante Stat, die verwendet
werden kann, um Werte vom Skalartyp Status in ihre entsprechende
Stringdarstellung zu konvertieren:
Stat[Aktiv] = 'aktiv'
Stat[Passiv] = 'passiv'
Stat[Wartend] = 'wartend'
Der Komponententyp einer Feldkonstanten kann jeder Typ sein
ausser einem Feld- oder Pointertyp. Charakterfeldtypen koennen
sowohl als einzelne Char als auch als Strings definiert werden.
Aus diesem Grunde ist es guenstiger statt:
const
Digits : array[0..9] of
Char=('0','1','2','3','4','5','6','7','8','9');
besser:
const
Digits : array[0..9] of Char='0123456789';
zu schreiben.
13.2.2 Mehrdimensionale Feldkonstante
Eine typisierte mehrdimensionale Feldkonstante wird analog defi-
niert, indem man jede Dimension in separate Klammernpaare ein-
schliesst, die durch Komma voneinander getrennt sind. Die inners-
te Konstant entspricht der am weitesten rechts stehenden Dimen-
sion:
Beipiele:
type
Cube = array[0..1,0..1,0..1] od integer;
const
Maze : Cube = (((0,1),(2,3)),((4,5),(6,7)));
begin
writeln(Maze[0,0,0],' =0');
writeln(Maze[0,0,1],' =1');
writeln(Maze[0,1,0],' =2');
writeln(Maze[0,1,1],' =3');
writeln(Maze[1,0,0],' =4');
writeln(Maze[1,0,1],' =5');
writeln(Maze[1,1,0],' =6');
writeln(Maze[1,1,1],' =7');
end;
.pa
13.2.3 Datensatzkonstante
Die Definition einer typisierten Datensatzkonstanten besteht aus
dem Konstantenbezeichner, einem Doppelpunkt, dem Typbezeichner
eines vorherdefinierten Datensatztyps, einem Gleichheitszeichen
und dem Konstantenwert. Letzterer ist eine Liste, die aus den
Datenfeldkonstanten, getrennt durch Komma und eingeschlossen in
runde Klammern, besteht.
Beipiele:
type
Point = record
X,Y,Z : integer;
end;
OS = (CPM80,CPM86,MSDOS,UNIX);
UI = (CCP,SomethingElse,MenuMaster);
Computer = record
OperatingSystems : array[1..4] of OS;
UserInterfacs : UI;
end;
const
Origo : Point = (X:0; Y:0; Z:0);
SuperComp : Computer=
(OperatingSystems:(CPM80,CPM86,MSDOS,UNIX);
UserInterface:MenuMaster);
Planel : array[1..3] of Point =
((X:1; Y:4; Z:5),
(X:10, Y:-78,Z:45),
(X:100,Y:10, Z:-75));
Die Feldkonstanten muessen in der gleichen Reihenfolge definiert
werden, wie sie in der Datensatzdefinition auftreten. Wenn ein
Datensatz Felder vom File- oder Pointertyp enthaelt, koennen
typisierte Konstanten fuer diesen Datensatztyp nicht definiert
werden. Wenn eine Datensatzkonstante eine Variante enthaelt, dann
ist der Programmierer selbst dafuer verantwortlich, dass nur die
Datenfelder der gueltigen Variante spezifiziert werden. Wenn die
Variante ein Kennzeichnungsfeld enthaelt, dann muss auch ihr Wert
spezifiziert werden.
13.2.4 Mengenkonstanten
Eine typisierte Mengenkonstante besteht aus einer oder mehreren
Elementenspezifikationen, die durch Komma getrennt und in eckigen
Klammern eingeschlossen sind. Eine Elementenspezifikation darf
eine Konstante oder ein Bereichsausdruck sein, der aus zwei
Konstanten, getrennt durch zwei Punkte, besteht.
Beipiele:
type
Up = set of 'A'..'Z';
Low = set of 'a'..'z';
const
UpperCase : Up = ['A'..'Z'];
Vocals : Low = ['a','e','i','o','u'];
Delimiter : set of Char =
[' '..'/',':'..'?','['..'`','{'..'~'];
.pa
14. Filetypen
Computerprogramme produzieren häufig so grosse Datenmengen, dass
man sie nicht bis zu einer spaeteren Verwendung im gleichen oder
anderen Programmen im Speicher belassen kann. Aus diesem Grunde
speichert man solche Datenmengen auf externen Datentraegern, wie
Magnetbandkassetten oder Disketten. Die Einheit einer solchen
Datenmenge heisst File oder Datei.
Ein File besteht aus einer Folge von Komponenten gleichen Typs.
Die Anzahl der Komponenten im File (die Filegroesse) wird nicht
in der Filedefinition festgelegt. Stattdessen wird in Pascal der
Zugriff zu den einzelnen Komponenten ueber einen Filepointer
organisiert. Jedesmal, wenn eine Komponente des Files gelesen
oder geschrieben wird, rueckt der Filepointer eine Komponente
weiter, d.h. er weist auf die naechste Komponente. Da alle Kompo-
nenten eines File die gleiche Laenge haben, weil sie vom gleichen
Typ sind, kann die Position einer bestimmten Komponente berechnet
werden d.h. man kann ueber den Filepointer zu jeder Komponente
des File zugreifen. Damit sind die Voraussetzungen gegeben, einen
wahlfreien Zugriff zu den Komponenten des File aufzubauen.
14.1 Filetyp-Definition
Ein Filetyp wird durch die reservierten Worte file of, denen der
Typbezeichner der Komponenten folgt, definiert. Eine Filevariable
wird definiert durch einen Filevariablenbezeichner, einem Doppel-
punkt und einen Filetyp. Dabei gibt es zwei Moeglichkeiten,
jenachdem, ob der Filetyp mit einem Filetypbezeichner explizit im
Typdefinitionsteil definiert wurde oder nicht:
1) type Komponente = record
x,y,z : integer;
end;
Filetyp = file of Komponente;
var FileVar : Filetyp;
oder
2) type Komponente = record
x,y,z : integer;
end;
var FileVar : file of Komponente
Beispiele:
type
ProductName = string[80];
Product = record
Name : ProductName;
ItmNumber : Real;
InStock : Real;
MinStock : Real;
Supplier : Integer;
end;
FProduct = file of Product;
var
ProductFiles : FProduct;
ProductNames : file of ProductName;
Der Komponententyp eines Files kann irgend ein Typ sein, jedoch
kein Filetyp!, d.h. in obigem Beispiel ist
var ProdFile : file of FProduct
nicht erlaubt.
.pa
Man beachte auch, dass zwar var P1File : FProduct;
und P2File : FProduct;
den gleichen Filetyp haben, aber nicht:
var PM1File : file of Product;
und PM2File : file of Product;
Weiterhin merke man sich: Filevariable duerfen weder in Ergibtan-
weisungen noch in Ausdruecken auftreten.
14.2 Fileoperationen
In den folgenden Abschnitten werden die in TURBO-Pascal vorhande-
nen Fileprozeduren beschrieben. Dabei werden folgende Kurzzeichen
fuer die Parameter verwendet:
str Stringausdruck, der einen gueltigen Filenamen in
der bekannten Form
'[A:]Dateinam.Typ'
darstellen muss.
filvar Filevariable.
var Eine Variable oder mehrere Variable, die dann
durch Komma getrennt sein muessen, und die alle
den gleichen Komponententyp wie das File haben
muessen.
num Integerkonstante.
14.2.1 Assign
Syntax: Assign(filvar,str)
Durch diese Prozedur wird der in str enthaltene physische Filena-
men der Filevariablen filvar zugewiesen. Danach beziehen sich
alle auf filvar ausgeuebte Operationen auf das genannte physische
Diskettenfile. Wurde der Filevariablen bereits ein physischer
Filenamen zugewiesen, und mit der Filevariablen gearbeitet, darf
ein erneutes ASSIGN auf sie nicht angewendet werden.
14.2.2 Rewrite
Syntax: Rewrite(filvar)
Mit dieser Prozedur wird auf der Diskette ein neues File mit dem
filvar zugewiesenen physischen Filenamen aufgebaut. Der Filepoin-
ter wird dabei auf den Anfang des File, d.h. auf die Komponente
mit der Nummer 0, gesetzt. Existiert auf der Diskette bereits der
gleiche physische Filenamen, dann wird das zugehoerige File ge-
loescht! Ein mit REWRITE erzeugtes File ist anfangs immer leer
und enthaelt kein Element.
14.2.3 Reset
Syntax: Reset(filvar)
Das filvar zugewiesene File wird fuer die Verarbeitung vorberei-
tet und der Filepointer auf den Anfang des File, d.h. die Kompo-
nente mit der Nummer 0, gesetzt. Das zugewiesene File muss be-
reits existieren, sonst entsteht in I/O-Fehler.
.pa
14.2.4 Read
Syntax: Read(filvar,var)
Durch diese Prozedur werden die Variablen var nacheinander mit
dem Inhalt der Komponenten des filvar zugeordneten Files ge-
fuellt. Begonnen wird mit der Komponente, auf die der Filepointer
zeigt. Nach jeder Zuweisung wird der Pointer auf die naechste
Komponente eingestellt.
14.2.5 Write
Syntax: Write(filvar,var)
Durch diese Prozedur werden nacheinander der Inhalt der Variablen
var in die Komponenten des filvar zugewiesenen Files geschrieben.
Begonnen wird mit der Komponente, auf die der Filepointer zeigt.
Nach jedem Schreibvorgang wird der Pointer auf die naechste
Komponente eingestellt.
14.2.6 Seek
Syntax: Seek(filvar,num)
Der Filepointer des filvar zugeordneten Files wird durch diese
Prozedur auf die Komponente mit der Nummer num-1 eingestellt (die
1.Komponente hat die Nummer 0!). Um ein File zu erweitern,
braucht man nur den Filepointer auf die Komponente hinter der
letzten Komponente des File einzustellen.
14.2.7 Flush
Syntax: Flush(filvar)
Diese Prozedur wird eigentlich nur in Multi-User-Systemen benoe-
tigt, in denen mehrere Nutzer zum gleichen Diskettenfile zugrei-
fen koennen. Flush schreibt sofort den Update-Puffer auf die
Diskette zurueck und sichert damit nach Updatefunktionen, dass
die naechste Leseoperation wirklich als ein physisches Lesen
ausgefuehrt wird. Flush darf niemals auf ein geschlossenes
(CLOSE) File angewendet werden.
14.2.8 Close
Syntax: Close(filvar)
Diese Prozedur schliesst das filvar zugeordnete physische File
und schreibt den aktuellen Filestatus in das Diskettenvezeichnis.
In Multi-User-Systemen sollte man oefter diese Prozedur anwenden,
auch wenn nur gelesen wurde.
14.2.9 Erase
Syntax: Erase(filvar)
Diese Prozedur loescht das filvar zugeordnete File im Disketten-
verzeichnis. Wenn das File bereits eroeffnet wurde, d.h. RESET
oder REWRITE ausgefuehrt wurde, sollte man stets CLOSE vor ERASE
aufrufen.
.pa
14.2.10 Rename
Syntax: Rename(filvar,st)
Das filvar zugewiesene File erhaelt den in str enthaltenen neuen
Filenamen. Der neue Name wird in das Diskettenverzeichnis einge-
tragen und die weiteren Operationen von filvar werden dann mit
diesem File unter dem neuen Namen ausgefuehrt.
Man sollte RENAME niemals auf ein bereits eroeffnetes File anwen-
den. Ebenso sollte der Programmierer sichern, dass das mit str
benannte File nicht bereits auf der Diskette existiert. Sonst
entstehen doppelte Namen in der Direktory.
Die folgende Funktion gibt den Wert True zurueck, falls der im
Parameter spezifizierte Filenamen bereits in der Direktory exis-
tiert, andernfalls ist der Wert False:
function Exist(Filename:Boolean):Boolean;
var
File:file;
begin
Assign(File,FileName);
{$I-};
Reset(File);
{$I+};
if Ioresult <> 0 then Exist := False;
else Exist := True;
end;
14.3 Standardfilefunktionen
TURBO-Pascal enthaelt die folgenden Standardfilefunktionen:
14.3.1 EOF
Syntax: Eof(filvar)
Diese Boolesche-Funktion gibt den Wert True zurueck, wenn der
Filepointer das Fileende erreicht hat, d.h. hinter die letzte
Komponente des filvar zugewiesenen Files weist. Andernfalls ist
der zurueckgegebene Wert False.
14.3.2 FilePos
Syntax: FilePos(filvar)
Diese Integer-Funktion gibt den Wert der aktuellen Position des
Filepointer zurueck. Die erste Komponente hat den Wert 0.
14.3.3 FileSize
Syntax: FileSize(filvar)
Diese Integer-Funktion gibt den Wert der Groesse des filvar
zugeordneten Files zurueck, d.h. die Anzahl der Komponenten des
Files. Wenn FileSize(filvar) gleich Null ist, dann ist das File
leer.
.pa
14.4 Filenutzung
Bevor ein File benutzt werden kann, muss ASSIGN aufgerufen wer-
den, um der Filevariablen ein physisches File zuzuordnen. Vor
einer I/O-Operation sollte das File durch Aufruf von REWRITE oder
RESET eroeffnet werden. Damit zeigt der Filepointer auf die erste
Komponente des File, d.h. es ist FilePos(filvar)=0. Nach REWRITE
ist stets FileSize(filvar)=0. Ein Diskettenfile kann nur durch
Anfuegen von weiteren Komponenten hinter die letzte existierend
Komponente des File erweitert werden. Den Filepointer kann man
dafuer an das Fileende positionieren durch:
Seek(filvar,FileSize(filvar));
Nach Beendigung aller Input/Output-Operationen sollte man in
einem Programm stets die eroeffneten Files durch CLOSE schlies-
sen. Vergisst man dies, kann das zu Datenverlust fuehren, da das
Diskettenverzeichnis dann eventuell nicht dem letzten Stand des
Filestatus entspricht.
Das folgende Programm baut ein File mit dem Namen PRODUCTS.DTA
auf und schreibt 100 Saetze vom Typ Product auf das File. Das
File ist fuer einen wahlfreien Zugriff vorbereitet (d.h. die
Saetze koennen von jeder Stelle des File gelesen oder geschrieben
werden).
program InitProductFile;
const
MaxNumberOfProducts = 100;
type
ProductName = string[20];
Product = record
Name : ProductName;
ItemNumber : Integer;
InStock : Real;
Supplier : Integer;
end;
var
ProductFile : file of Product;
ProductRec : Product;
I : Integer;
begin
Assign(ProductFile,'F:PRODUCT.DTA');
Rewrite(ProductFile); {eroeffnet File und loescht alle Daten}
with ProductRec do
begin
Name := ' '; InStock := 0; Supplier := 0;
for I := 1 to MaxNumberOfProducts do
begin
ItemNumber := I;
Write(ProductFile,ProductRec);
end;
end;
Close(ProductFile);
end.
.pa
Das folgende Programm demonstriert die Verwendung von SEEK fuer
den wahlfreien Zugriff. Mit diesem Programm kann man in dem
soeben aufgebauten File PRODUCT.DTA den Inhalt in die bereits
existierenden Datensaetze (Komponenten) bringen oder den Inhalt
spaeter aendern.
program UpdateProductFile;
const
MaxNumberOfProducts = 100;
type
ProductName = string[20];
Product = record
Name : ProductName;
ItemNumber : Integer;
InStock : Real;
Supplier : Integer;
end;
var
ProductFile : file of Product;
ProductRec : Product;
I,Pnr : Integer;
begin
Assign(ProductFile,'F:PRODUCT.DTA');
Reset(ProductFile);
ClrScr;
Write('Enter product number (0 = stop):'); Readln(Pnr);
while Pnr in [1..MaxNumberOfProducts] do
begin
Seek(ProductFile,Pnr-1); Read(ProductFile,ProductRec);
with ProductRec do
begin
Write('Enter name of product(',name:20,') ');
Readln(Name);
Write('Enter number in stock (',InStock:20:0,') ');
Readln(InStock);
Write('Enter supplier number (',Supplier:20,') ');
Readln(Supplier);
ItemNumber := Pnr;
end;
Seek(ProductFile,Pnr-1);
Write(ProductFile,ProductRec);
ClrScr; Writeln;
Write('Enter product number (0 = stop):'); Readln(Pnr);
end;
Close(ProductFile);
end.
.pa