GNU-Pascal in Beispielen: Typen im Eigenbau

Aus Wikibooks
Wechseln zu: Navigation, Suche

zurück zu GNU-Pascal in Beispielen

Typen im Eigenbau[Bearbeiten]

Die grundlegenden Typen wurden bereits im Kapitel Variablen und Typen besprochen. Dieses Kapitel beschäftigt sich damit, auf der Basis dieser grundlegenden Typen eigene Typen zu entwickeln.

Üblicherweise wird selbstdefinierten Typen immer ein "T" vorangestellt.

Eigene Stringtypen[Bearbeiten]

Grundsätzlich ist an dieser Stelle bekannt, wie Strings mit einer bestimmten Kapazität erzeugt werden. Statt aber, wie in Kapitel Zeichenketten alle Strings mit ihrer Kapazität anzugeben, ist es viel bequemer, sich eigene Stringtypen selbst zu erzeugen:

Program: Stringtyp[Bearbeiten]

 program Stringtyp;
 
 const
   Kapazitaet = 20;
 
 type
   TMeinString = String (Kapazitaet);
 
 var
   MeinString: TMeinString;
 
 begin
   MeinString := 'Hallo, Welt!';
   WriteLn (MeinString)
 end.

Erklärung[Bearbeiten]

Im Bereich von type werden eigene Typen definiert. TMeinString ist damit ab sofort ein Synonym für String (20). Dieser Typ kann im var-Bereich sofort genutzt werden.

Die hier gezeigte Reihenfolge von const, type und var ist die natürlichste Art der Anordnung. Wenn keine Gründe gegen diese Reihenfolge sprechen, so sollte sie beibehalten werden.

Eigene ganzzahlige Typen[Bearbeiten]

Manchmal ist es nützlich, eigene ganzzahlige Typen zu definieren. Das folgende Programm demonstriert die Vorgehensweise:

Program: Integertyp[Bearbeiten]

 program Integertyp;
 
 type
   TMeinInteger = Integer (3);
   TMeinCardinal = Cardinal (3);
 
 begin
   WriteLn ('Kleinster TMeinInteger Wert:  ', Low (TMeinInteger));
   WriteLn ('Groesster TMeinInteger Wert:  ', High (TMeinInteger));
   WriteLn ('Kleinster TMeinCardinal Wert: ', Low (TMeinCardinal));
   WriteLn ('Groesster TMeinCardinal Wert: ', High (TMeinCardinal))
 end.

Erklärung[Bearbeiten]

Es werden zwei verschiedene ganzzahlige Typen definiert, wobei einer vorzeichenbehaftet, der Andere vorzeichenlos ist. Beide haben eine Kapazität von drei Bits. Die Funktion Low liefert den kleinsten Wert, den eine Variable von diesem Typ annehmen kann, die Funktion High den Höchsten.

Records[Bearbeiten]

Records sind aus beliebigen Typen in beliebiger Anzahl zusammengesetzte Typen. Ein Record könnte so beispielsweise alle Anschriftendaten über Personen zusammenfassen, geometrische Figuren organisieren oder die Informationen einer /etc/passwd-Datenzeile gruppieren.

Arbeiten mit Records[Bearbeiten]

Ein Record wird definiert, indem alle "Record-Felder" aufgeführt werden:

Program: Record1a[Bearbeiten]
 program Record1a;
 
 type
   TEintrag = String (100);
   TPostleitzahl = String (5);
 
   TMitarbeiter = record
     PersonalNummer: Integer;
     Vorname, Nachname, Strasse, Stadt: TEintrag;
     PLZ: TPostleitzahl
   end;
     
 var
   Person: TMitarbeiter;
 
 begin
   Person.PersonalNummer := 7;
   Person.Vorname        := 'Hans';
   Person.Nachname       := 'Dampf';
   Person.Strasse        := 'In den Gassen 1-100';
   Person.Stadt          := 'Ueberall';
   Person.PLZ            := '12345'
 end.
Erklärung[Bearbeiten]

Gefolgt von dem Schlüsselwort record werden die einzelnen Felder wie bei der Variablendeklaration aufgeführt. Eine Initialisierung während der Typendefinition ist nicht möglich. Der Record endet mit dem abschließenden end. Auf die einzelnen Felder eines Records wird mit Hilfe der Punkt-Schreibweise zugegriffen. So meint Person.Stadt das "Stadt-Feld" des Records.

Records können bei der Variablendeklaration initialisiert werden, wie folgendes Beispiel zeigt:

Program: Record2[Bearbeiten]
 program Record2;
 
 type
   TPunkt = record
     X, Y: Integer
   end;
   TKreis = record
     Mitte: TPunkt;
     Radius: Real
   end;
 
 var
   Ort: TPunkt = (100, 50);
   Kreis: TKreis = ((19, 23), 30.1);
 
 begin
   WriteLn ('Ort = (', Ort.X, ';', Ort.Y, ')');
   WriteLn ('Kreis = (', Kreis.Mitte.X, ';', Kreis.Mitte.Y,') Radius = ',
    Kreis.Radius : 0 : 2)
 end.
Erklärung[Bearbeiten]

Es werden zwei Record-Typen erzeugt, TPunkt und TKreis, wobei TKreis TPunkt als Feld Mitte enthält. Die Variablendeklaration Ort initialisiert die zwei Feldvariablen mit Hilfe von (100, 50), sodass Ort.X = 100 und Ort.Y = 50 ist.

Kreis hingegen wird so initialisiert, dass Kreis.Mitte wie Ort initialisiert wird, diesmal allerdings zu (19, 23). Die Feldvariable Radius wird mit der Zahl 30.1 initialisiert. Beachten Sie dabei die geschachtelte Klammerung.

Der Zugriff auf die Record-Felder erfolgt wieder in der Punkt-Schreibweise. Ort.X ist die X-Koordinate des Punktes, Kreis.Radius der Radius des Kreises. Der Mittelpunkt des Kreises ist Kreis.Mitte, seine X-Koordinate lautet Kreis.Mitte.X.

Ein häufiges Einsatzgebiet von Records ist das Speichern von Datensätzen innerhalb von Arrays. Folgendes Beispiel demonstriert das Vorgehen:

Program: Record3[Bearbeiten]
 program Record3;
  
 const
   IndexEnde = 10;
  
 type
   TPunkt = record
     X, Y: Integer
   end;
  
   TPunkte = array [1..IndexEnde] of TPunkt;
  
 var
   Orte: TPunkte;
   Index: Integer;
  
 begin
   for Index := 1 to IndexEnde do
     begin
       Orte[Index].X := Index;
       Orte[Index].Y := Index * 2
     end;
   for Index := 1 to IndexEnde do
     WriteLn ('Orte[', Index, '] = (',
       Orte[Index].X, ';', Orte[Index].Y, ')')
 end.
Erklärung[Bearbeiten]

Die Deklaration des Arrays erfolgt wie bei elementaren Typen, lediglich die Initialisierung ist verschieden: Auf die einzelnen Record-Felder wird gesondert zugegriffen.


With[Bearbeiten]

Der Zugriff auf die einzelnen Komponenten des Arrays aus Beispiel Record1 ist schon bei wenigen Feldern sehr mühsam zu schreiben. Jedes Mal musste "Person." vor das gemeinte Feld notiert werden. Eine abkürzende Schreibweise auf Record-Komponenten demonstriert folgendes Beispiel:

Program: Record1b[Bearbeiten]
 program Record1b;
  
 type
   TEintrag = String (100);
   TPostleitzahl = String (5);
  
   TMitarbeiter = record
     PersonalNummer: Integer;
     Vorname, Nachname, Strasse, Stadt: TEintrag;
     PLZ: TPostleitzahl
   end;
     
 var
   Person: TMitarbeiter;
  
 begin
   with Person do
     begin
       PersonalNummer := 7;
       Vorname        := 'Hans';
       Nachname       := 'Dampf';
       Strasse        := 'In den Gassen 1-100';
       Stadt          := 'Ueberall';
       PLZ            := '12345'
     end
 end.
Erklärung[Bearbeiten]

Die abkürzende Schreibweise mit with erspart das mehrfache Schreiben von "Person.". Trotz dieser Struktur darf innerhalb des with-Blockes weiterhin Person.Nachname geschrieben werden, wenn es der Umstand erfordert. With-Blöcke dürfen beliebig geschachtelt werden, wobei darauf zu achten ist, dass nicht mehrere Record-Variablen die gleichen Feldbezeichner haben. Fehler, die daraus resultieren, sind schwer zu finden.

Variante Records[Bearbeiten]

Erweiterten wir die Menge der geometrischen Objekte aus Record2 um einige weitere Typen, so würden wir schnell feststellen, dass sie gemeinsame Eigenschaften haben die es nahelegen, alle diese Typen in einem gemeinsamen Record zu vereinigen. Eine Möglichkeit könnte darin bestehen, alle diese Typen einzeln in das Record aufzunehmen, wie folgendes Beispiel zeigt:

Program: Variant1[Bearbeiten]
 program Variant1;
 
 type
   TObjektTyp = (Punkt, Kreis, Rechteck);
 
   TPunkt = record
     X, Y: Integer
   end;
 
   TKreis = record
     X, Y: Integer;
     Radius: Real
   end;
 
   TRechteck = record
     X, Y, Breite, Hoehe: Integer
   end;
 
   TGeometrie = record
     Typ: TObjektTyp;
     Punkt: TPunkt;
     Kreis: TKreis;
     Rechteck: TRechteck
   end;
 
 begin
   WriteLn ('Größe TObjektTyp = ', SizeOf (TObjektTyp));
   WriteLn ('Größe TPunkt     = ', SizeOf (TPunkt));
   WriteLn ('Größe TKreis     = ', SizeOf (TKreis));
   WriteLn ('Größe TRechteck  = ', SizeOf (TRechteck));
   WriteLn ('Größe TGeometrie = ', SizeOf (TGeometrie))
 end.
Erklärung[Bearbeiten]

In diesem Beispiel werden alle Typen in einem Record zusammengefasst. die Funktion SizeOf liefert uns die Größe eines Objektes in Bytes. Bei diesem Beispiel stellt sich der Nachteil ein, dass TGeometrie die gleiche Größe hat, wie die Summe der einzelnen Typen.

Eine wesentlich elegantere Art, TGeometrie zu definieren ist folgende:

Program: Variant2[Bearbeiten]
 program Variant2;
 
 type
   TObjektTyp = (Punkt, Kreis, Rechteck);
 
   TGeometrie = record
     X, Y: Integer;     { gemeinsam für alle Geometrie-Typen }
     case Typ: TObjektTyp of
       Kreis:    (Radius: Real);
       Rechteck: (Breite, Hoehe: Integer)
   end;
 
 var
   MeinKreis, MeinPunkt: TGeometrie;
 
 begin
   WriteLn ('Größe TGeometrie = ', SizeOf (TGeometrie));
 
   with MeinKreis do
     begin  
       Typ := Kreis;
       X := 10;
       Y := 10;
       Radius := 3.0
     end;
 
   with MeinKreis do
     WriteLn ('(', X, ';', Y, ') R= ', Radius);
 
   with MeinPunkt do
     begin
       Typ := Punkt;
       X := 20;
       Y := 20
     end;
 
   with MeinPunkt do
     WriteLn ('(', X, ';', Y, ')')
 end.
Erklärung[Bearbeiten]

Diejenigen Record-Felder, die allen Geometrietypen gemeinsam waren, wurden in der neuen Definition von TGeometrie an den Anfang des Records gestellt. Danach folgt eine Auswahl der Record-Felder mittels case Typ: TObjektTyp of. Das Record-Feld Typ wird tatsächlich zum Bestandteil des Records, diese Art der Darstellung erlaubt es, aus der Menge von Varianten Kreis und Rechteck beschreibend auszuwählen. Wenn Typ = Kreis ist, so steht uns das Record-Feld Radius zur Verfügung, ist Typ = Rechteck, dann sind Breite und Hoehe verfügbar [1].

Der Fall Typ = Punkt braucht nicht gesondert abgefangen zu werden, seine Beschreibung liegt außerhalb der Varianten im oberen Bereich des Records. Die Größe des jetzigen TGeometry-Typs ist nur noch das Maximum der Größe der Varianten plus der Größe der außerhalb des Varianten-Teils liegenden Record-Felder. Eine Variable vom Typ TGeometry benötigt mit dieser Methode ungefähr die Hälfte des Speichers, den eine entsprechende Variable aus Variant1 belegen würde.

Zeiger[Bearbeiten]

Alle bisher beschriebenen Variablendeklarationen gingen davon aus, dass wir eine zum Zeitpunkt des Programmierens bekannte Anzahl von Datenelementen speichern wollen. Ist die Anzahl der Elemente, die wir speichern wollen aber beliebig und die Typen vielleicht unterschiedlich, so helfen Zeiger dabei, eine dynamische Speicherverwaltung zu erzeugen. Ein Zeiger ist lediglich ein Verweis auf die Speicherstelle einer Variablen [2]. Ein einführendes Beispiel mit Zeigern zeigt folgendes Listing:

Program: Zeiger[Bearbeiten]

 program Zeiger;
 
 type
   PInteger = ^Integer;
 
 var
   RefZahl: PInteger = nil;
 
 begin
   New (RefZahl);
   RefZahl^ := 42;
   WriteLn ('Inhalt  = ', RefZahl^);
   WriteLn ('Adresse = ', Cardinal (RefZahl));
   Dispose (RefZahl)
 end.

Erklärung[Bearbeiten]

Ein Zeigertyp wird definiert, indem ein Dach "^" vor den Grundtyp gestellt wird. Das Bedeutet in obigem Fall "Zeiger auf Integer". Allgemeine Zeiger auf nicht näher spezifizierte Typen sind Pointer.

Deklariert werden Variablen von Zeigertypen genauso wie von allen anderen Typen, neu ist die Initialisierung mit dem Schlüsselwort nil. Es sollte hier am Anfang des Kapitels nur der Vollständigkeit aufgeführt werden und bedeutet einen Zeiger auf "nichts", also einen leeren Zeiger [3]. Die Prozedur New erzeugt den Speicherplatz, auf dem in Zukunft ein Wert vom Typ Integer liegen soll. Dieser Wert kann zugewiesen werden, wobei das Dach diesmal nachgestellt wird. Diese Art des Zugriffs nennt man dereferenzieren. Auf die gleiche Weise kann der Inhalt des Zeigers ausgegeben werden.

Der Zeiger selbst kann mit Hilfe eines Casts ausgegeben werden, wobei hier die Speicheradresse ermittelt [4] wird, an der die Zahl 42 abgelegt wurde [5].

Dispose gibt den Speicherplatz, der mit New erzeugt wurde, wieder frei. Obwohl der Speicher freigegeben wurde, verweist der Zeiger möglicherweise noch an die Position, wo die Zahl 42 abgelegt wurde. Verlassen sollte man sich darauf auf keinen Fall, denn ein freigewordener Speicher kann jeden beliebigen Wert haben, auch den ursprünglichen. Erst beim erneuten Überschreiben der Speicheradresse durch das Betriebssystem ändert sich dieser Wert.

Zeigertypen sollte, so lange nichts dagegen spricht, immer ein "P" vorrangestellt werden.

Ein weitaus komplexeres Beispiel der Speicherverwaltung stellen so genannte Stapel dar. Ein Stapel ist eine Datenstruktur, bei der neu eingefügte Daten über [6] alle anderen Daten gestellt werden. Diejenigen Daten, die zuerst eingegeben wurde sind die Untersten des Stapels. Schaut man sich die einzelnen Elemente des Stapels an, so beginnt man von oben, also in umgekehrter Reihenfolge der Eingabe der Daten. Das folgende Programm liest einen "Stapel Namen" ein, gibt ihn aus und löscht ihn anschließend wieder:

Program: Stapel1[Bearbeiten]

 program Stapel1;
 
 type
   TNamenString = String(100);
   PNamen = ^TNamen;
   TNamen = record
     Name: TNamenString;
     Naechster: PNamen
   end;
 
 var
   NamenStapel, TempName: PNamen = nil;
   Abbruch: Boolean = False;
   Name: TNamenString;
   Nummer: Integer;
 
 begin
   Write ('Erzeugt eine Namensliste. ');
   WriteLn ('Abbruch durch leere Zeile');
   { Namensstapel aufbauen }
   repeat
     Write ('Geben Sie einen Namen ein: ');
     ReadLn (Name);
     if Length (Name) = 0 then
       Abbruch := True
     else
       begin
         { neuen Speicherplatz reservieren }
         New (TempName);
         { Namen eintragen }
         TempName^.Name := Name;
         { alten Stapel unter den Neuen legen }
         TempName^.Naechster := NamenStapel;
         {  Alter Stapel ist neuer Stapel }
         NamenStapel := TempName
       end
   until Abbruch;
 
   TempName := NamenStapel;  { oberstes Stapelelement }
   Nummer := 1;
 
   { Namensstapel ausgeben }
   while TempName <> nil do
     begin
       WriteLn (Nummer, 'ter Name: ', TempName^.Name);
       Inc (Nummer);
       TempName := TempName^.Naechster
     end;
  
   { Namensstapel loeschen }
   TempName := NamenStapel;  { oberstes Stapelelement }
   while TempName <> nil do
     begin
       { Namenstapel zeigt auf zweites Element }
       NamenStapel := NamenStapel^.Naechster;
       WriteLn ('entferne ', TempName^.Name);
       Dispose (TempName);      { Speicher wieder freigeben }
       TempName := NamenStapel  { oberstes Stapelelement }
     end
 end.

Erklärung[Bearbeiten]

Im Typenbereich werden drei Typen deklariert, einer für Strings mit einer festen Größe (TNamenString), ein Zeiger auf einen Record (PNamen) und der Record selber (TNamen). Auffällig ist, dass der Zeigertyp (PNamen) vor dem Typen (TNamen), dessen Verweis er ist, deklariert wurde. Dies ist erlaubt und an dieser Stelle auch durchaus erwünscht, denn innerhalb der Definition des Records TNamen wird dieser Zeigertyp als Typ des Record-Feldes Naechster eingesetzt. Verweist ein Record-Feld auf diese Weise auf sich selbst, so spricht man von einer "rekursiven Datenstruktur".

Der Namensstapel wird wie folgt aufgebaut: Wurde ein "richtiger Name" eingegeben, so wird mit Hilfe der Prozedur New ein Speicherplatz für TNamen erzeugt. Der Name wird dem Record-Feld Name zugewiesen. Dabei wird mit Hilfe des Daches der Zeiger dereferenziert, so dass eine Variable vom Typ TNamen vorliegt.

Auf die Record-Felder dieser Variablen greift man mit der bekannten "Punkt-Schreibweise" zu. Das Feld Naechster wird mit dem Zeiger auf den alten Stapel belegt, wobei dieser "alte Stapel" beim ersten Durchlauf nil ist. Der Zeiger Namensstapel, welcher soeben noch einen Zeiger auf das erste Element des restlichen Stapels war, wird nun zu einem Zeiger auf das oberste Element des Stapels. Auf diese Weise wird fortwährend der alte Stapel unter das neu erzeugte Element TempName gelegt.

Die Daten des Namensstapels werden ausgegeben, indem der Stapel von "oben nach unten" durchlaufen wird. Am Anfang zeigt TempName auf das oberste Element des Stapels und wird bei jedem Durchlauf auf seinen Nachfolger gesetzt, die Anzahl der Stapelelemente wird zwecks Anzeige mitprotokolliert. Beachten Sie, dass die Reihenfolge der Ausgabe in umgekehrter Reihenfolge der Eingabe erfolgt. Speicher, der dynamisch alloziert [7] wurde, muss spätestens zum Ende des Programms wieder freigegeben werden. TempName verweist zu Beginn auf das oberste Stapelelement. Solange der Stapel noch nicht vollständig abgebaut wurde, wird die Variable NamenStapel auf das Element hinter TempName gesetzt. Damit enthält NamenStapel wieder den "Rest" des Stapels. Der Speicher des obersten Elementes wird mit Dispose entfernt. Dieser nun freigewordene Zeiger kann anschließend wieder auf das erste Element des Stapels gesetzt werden und die Schleife kann erneut durchlaufen werden.


Schemata[Bearbeiten]

Schemata dienen ebenso wie Zeiger dazu, Speicher dynamisch zu verwalten. Im Gegensatz zu Zeigern muss die maximale Anzahl der Elemente, die gespeichert werden sollen, bekannt sein, wobei diese Anzahl erst zur Laufzeit feststehen muss. Einen Schematypen kennen Sie bereits, es handelt sich dabei um Strings. Schemata und Zeiger lassen sich auch kombinieren. Das einführende Beispiel zeigt den grundsätzlichen Umgang mit Schemata:

Program: Schema1[Bearbeiten]

 program Schema1;
 
 type
   TSchemaType (Anz: Byte) = array [1..Anz] of Integer;
 
 var
   MeinSchema: TSchemaType (4);
   i: Integer;
 
 begin
   WriteLn ('MeinSchema hat maximal ', MeinSchema.Anz, ' Elemente.');
   for i := 1 to MeinSchema.Anz do
     MeinSchema[i] := 5 * i;
   for i := 1 to MeinSchema.Anz do
     WriteLn (MeinSchema[i])
 end.

Erklärung[Bearbeiten]

Schematypen werden definiert, indem mindestens eine Variable, in unserem Beispiel Anz, dem Typenname folgt. Diese Variable, die auch als Diskiminante bezeichnet wird, wird als eine der Grenzen eines Arrays [8] benutzt. Das Deklarieren eines Schemas erfolgt analog zum Deklarieren eines Strings.

Die maximale Anzahl der Elemente wird angegeben, was in unserem Fall bedeutet, dass MeinSchema ein Array von vier Integer-Variablen ist. Die Anzahl der Elemente lässt sich nachträglich während des Programmlaufes herausfinden, indem das zum Schema passende Feld Anz in der bekannten Weise ausgelesen wird. Auf die Variable MeinSchema kann zugegriffen werden, wie auf ein Array.

Schemata dienen der Bequemlichkeit. Benötigt man mehrere Variablen vom gleichen Array-Typ, jedoch mit möglicherweise unterschiedlicher Anzahl von Variablen, so sind sie genau die richtige Wahl.

mehrdimensionale Arrays zu erzeugen oder den Anfang und das Ende des Arrays festzulegen, wie folgendes Beispiel zeigt:

Program: Schema2[Bearbeiten]

 program Schema2;
 
 type
   TSchemaType (Anfang, Ende: Cardinal) = 
     array [Anfang..Ende] of Integer;
 
 var
   MeinSchema: TSchemaType (1, 4) = (5, 6, 7, 8);
   i: Integer;
 
 begin
   for i := MeinSchema.Anfang to MeinSchema.Ende do
     WriteLn (MeinSchema[i])
 end.

Erklärung[Bearbeiten]

In diesem Beispiel werden mit Hilfe der beiden Diskriminanten Anfang und Ende die Grenzen des Arrays festgelegt. Diese Grenzen müssen bei der Deklaration der Variablen angegeben werden. Wie auf diese Diskriminanten zugegriffen wird, zeigt die for-Schleife.

Schemata können mit Zeigern kombiniert werden und zur Laufzeit dynamisch erzeugt werden. Das folgende Programm ist eine Abwandlung von Schema2 welches diese Fähigkeit demonstriert:

Program: Schema3[Bearbeiten]

 program Schema3;
 
 type
   PSchemaType = ^TSchemaType;
   TSchemaType (Anfang, Ende: Cardinal) = array [Anfang..Ende] of Integer;
 
 var
   MeinSchema: PSchemaType;
   i: Integer;
 
 begin
   New (MeinSchema, 4, 6);
   for i := MeinSchema^.Anfang to MeinSchema^.Ende do
     MeinSchema^[i] :=  10 * i;
   for i := MeinSchema^.Anfang to MeinSchema^.Ende do
     WriteLn (MeinSchema^[i]);
   Dispose (MeinSchema)
 end.

Erklärung[Bearbeiten]

Es wird ein Zeiger auf den Schematyp definiert, der genutzt wird, um MeinSchema zu deklarieren. Der Speicher für MeinSchema wird dynamisch angefordert, wobei der Prozedur New beide Grenzen des zugehörigen Arrays übergeben werden. Auf Anfang und Ende wird mit der bekannten Zeiger-Schreibweise zugegriffen, als sei MeinSchema ein Record [9]. Das Array erhält man, indem der Schemazeiger dereferenziert wird. Auf die einzelnen Variablen kann sodann mit der Index-Schreibweise zugegriffen werden.


Anmerkungen[Bearbeiten]

  1. Aktuell ist es prinzipiell möglich, alle verfügbaren Record-Felder zu überschreiben, unabhängig davon, wie Typ belegt wurde. Hierauf muss bei der Programmierung selbst geachtet werden.
  2. So wie die Adresse einer Person nicht die Person selber bedeutet sondern einen Verweis auf sie.
  3. Stellen Sie sich ruhig einen Zeiger auf "nichts" wie eine leere, noch nicht ausgefüllte Anschrift vor.
  4. An die wir einen Brief schicken könnten mit der Frage nach ihrem Inhalt.
  5. Die wir mit Hilfe der verschachtelten Typencasts
    Integer (Pointer (Cardinal (RefZahl))^)
    
    
    wieder erhalten könnten.
  6. Wie bei einem Stapel Teller: Der zuletzt auf den Stapel gelegte Teller ist der Oberste.
  7. So nennt man das Zuteilen von Speicher, zum Beispiel mit der Prozedur New.
  8. Schemata müssen nicht, so wie in unseren Beispielen, auf Arrays basieren, aber es ist vermutlich das häufigste Einsatzgebiet.
  9. Tatsächlich sind Schemata wie Records implementiert.


Wikibooks buchseite.svg Zurück zu Kontrollstrukturen | One wikibook.svg Hoch zu Inhaltsverzeichnis | Wikibooks buchseite.svg Vor zu Routinen