Programmierkurs: Delphi: Pascal: Arrays

Aus Wikibooks

Arrays[Bearbeiten]

Was sind Arrays?[Bearbeiten]

Ein Array ist vereinfacht gesagt, eine Liste von Werten des gleichen Datentyps.

Arrays anlegen[Bearbeiten]

Wir wollen eine Gästeliste mit 10 Gästen anfertigen. Bisher hätten wir in etwa folgendes gemacht:

var
  gast1, gast2, gast3, gast4, gast5, gast6, gast7, gast8, gast9, gast10: string;


Der Nachteil dieses Verfahrens liegt auf der Hand - spätestens wenn zwanzig Gäste kommen.

Nun erzeugen wir einfach ein Array vom Datentyp String mit 10 Elementen:

var
  gaeste: array[1..10] of string;


Die genaue Struktur der Array-Deklaration ist:

array [<startindex> .. <endindex>] of <Datentyp>;


startindex..endindex ist dabei eine so genannte Bereichsstruktur mit dem wir den Bereich zwischen Startwert und Endwert angeben (Randwerte werden mit eingeschlossen). Es ist auch möglich, einen Bereich wie -3..5 anzugeben.

Der Name einer Array-Variablen sollte immer ein Substantiv sein und in der Mehrzahl stehen.

Auf Arrays zugreifen[Bearbeiten]

Um nun auf die einzelnen Elemente zuzugreifen, verwenden wir folgende Syntax:

gaeste[1] := 'Axel Schweiß';
gaeste[2] := 'Peter Silie';
gaeste[3] := 'Jack Pot';
gaeste[4] := 'Ngolo Kante';
gaeste[5] := 'Manuel Neuer';
{ ... },


Die Zahl in den eckigen Klammern ist der so genannte Index. Er gibt an, auf welches Element des Arrays wir zugreifen wollen. Gültige Werte sind hier die Zahlen 1 bis 10. Ein weiterer Vorteil von Arrays ist, dass wir anstatt eines fixen Indexes auch einen ordinalen Datentyp angeben können. Das heißt z.B. eine Integer-Variable. Die Abfrage der Namen von 10 Gästen ließe sich also so sehr einfach implementieren:

var
  index: Integer;
  gaeste: array[1..10] of string;
begin
  for index := 1 to 10 do
  begin
    Writeln('Bitte geben Sie den Namen des ', index, '. Gastes ein:');
    Readln(gaeste[index]);
  end;
end.


Dynamische Arrays[Bearbeiten]

Ändern wir unser Szenario so ab, dass wir eine Gästeliste erstellen wollen, aber nicht wissen, wieviele Gäste diese beinhalten soll. Nun könnten wir zwar ein Array erzeugen, das auf jeden Fall groß genug ist um alle Gäste der Welt aufzunehmen. Allerdings wäre dies eine Verschwendung von Speicher und nicht gerade effektiv. Hier kommen uns die dynamischen Arrays zu Hilfe. Dabei handelt es sich, wie man vielleicht vermuten kann, um Arrays, deren Länge man zur Laufzeit verändern kann. Erstellt werden sie praktisch genauso wie normale Arrays, nur geben wir diesmal keinen Indexbereich an:

var
  gaeste: array of string;


Der Indexbereich eines dynamischen Arrays ist zwar dynamisch, aber er beginnt zwingend immer mit 0. Zu Beginn hat dieser Array die Länge 0, d.h. er beinhaltet momentan keine Werte.

Länge des Arrays verändern[Bearbeiten]

Nun verändern wir die Länge des Arrays auf 10:

SetLength(gaeste, 10);


Unser Array hat nun eine Länge von 10. Das bedeutet, wir können 10 Strings in ihm verstauen. Allerdings hat das höchste Element im Array den Index 9. Das liegt daran, dass das erste Element den Index 0 hat und wir daher mit dem Index 9 schon 10 Elemente zusammen haben.

Nun könnten wir zum Einlesen unserer Gästeliste so vorgehen:

var
  index, anzahlgaeste: Integer;
  gaeste: array of string;
begin
  Writeln('Bitte geben Sie die Anzahl der Gäste ein:');
  Readln(anzahlgaeste);
  SetLength(gaeste, anzahlgaeste);
  for index := 0 to anzahlgaeste-1 do
  begin
    Writeln('Bitte geben Sie den Namen des ', index + 1, '. Gastes ein:');
    Readln(gaeste[index]);
  end;
end.


Dies würde zwar zum gewünschten Erfolg führen, allerdings benötigen wir so ständig eine weitere Variable, die die Länge unseres Arrays angibt. Um dies zu umgehen, bedienen wir uns der Routinen High und Low.

Erster und letzter Index[Bearbeiten]

Die Routine High liefert den höchsten Index des übergeben Arrays zurück:

Code:

SetLength(gaeste, 10);
Writeln(High(gaeste));

SetLength(gaeste, 120);
Writeln(High(gaeste));

Ausgabe:

9
119


Die Routine Length gibt, wie sich vermuten lässt, die Länge des Arrays zurück:

Code:

SetLength(gaeste, 10);
Writeln(Length(gaeste));

Ausgabe:

10


Mit der Routine Low ermitteln Sie den ersten Index des übergebenen Arrays. Bei einem dynamischen Array wäre dies immer 0. Daher benötigt man diese Funktion in einem realen Programm eigentlich nicht. Lediglich bei Arrays mit festen Indexbereichen erhält diese Funktion einen tieferen Sinn. So kann man auf einfache Weise den unteren Index abändern, indem man diesen einfach in der Deklaration überschreibt. Um den Rest des Programms braucht man sich dann nicht zu kümmern, da man mit Low auf der sicheren Seite ist.

Nun können wir unser Programm ein weiteres bisschen vereinfachen. Um die Funktionsweise eines dynamischen Array deutlich zu machen, fragen wir auch nicht mehr nach der Anzahl der Gäste, sondern fragen so lange nach weiteren Namen, bis das Ganze mit einer leeren Eingabe beendet wird:

var
  name: string;
  gaeste: array of string;
begin
  repeat
    Writeln('Bitte geben Sie den Namen des ', Length(gaeste) + 1, '. Gastes ein (leer zum Beenden):');
    Readln(name);
    if (name <> '') then
    begin
      SetLength(gaeste, Length(gaeste) + 1);
      gaeste[High(gaeste)] := name;
    end;
  until (name = '');
end.


Hier wird nach jeder Eingabe eines Namens das Array vergrößert und dann der Name am Ende der Liste eingetragen. Dies hat den Vorteil, dass die Liste zu jedem Zeitpunkt immer nur die benötigte Größe hat und keine unnötigen leeren Elemente an deren Ende enthält. Man benötigt in diesem Beispiel dadurch zwar einen zusätzlichen Prüfblock und kann das Array nicht mehr direkt befüllen, spart sich aber gleichzeitig eine Variable. In komplexeren Programmen, bei denen man nicht einfach jemanden nach der Anzahl der Werte fragen kann (z.B. beim Auslesen von Datensätzen aus einer Datei) ist diese Programmiertechnik sehr hilfreich, wenn nicht gar notwendig.

Array freigeben[Bearbeiten]

Da wir beim Erstellen des Arrays Speicher belegt haben, müssen wir diesen noch freigeben. Das geschieht ganz einfach mittels:

SetLength(gaeste, 0);


Dabei wird die Länge des Arrays wieder auf 0 gesetzt und er beansprucht so keinen weiteren Platz im Speicher mehr. Dies sollte man allerdings immer dann ausführen, wenn der verwendete Array nicht mehr benötigt wird. Unser finales Programm sieht also so aus (wieder etwas vereinfacht mit abgefragter Anzahl der Gäste):

var
  index, anzahlgaeste: Integer;
  gaeste: array of string;
begin
  Writeln('Bitte geben Sie die Anzahl der Gäste ein:');
  Readln(anzahlgaeste);
  SetLength(gaeste, anzahlgaeste);
  for index := 0 to High(gaeste) do
  begin
    Writeln('Bitte geben Sie den Namen des ', index + 1, '. Gastes ein:');
    Readln(gaeste[index]);
  end;
  SetLength(gaeste, 0);
end.


Mehrdimensionale Arrays[Bearbeiten]

Bis jetzt haben wir uns nur mit eindimensionalen Arrays beschäftigt. Wir haben in Pascal aber auch die Möglichkeit, mehrdimensionale Arrays anzulegen. Dabei kann jeder Unterbereich mit einem festen oder dynamischen Indexbereich versehen sein. Ein mehrdimensionales Array kann man sich wie eine Tabelle vorstellen, was bei zwei und drei Indexbereichen noch nicht schwerfallen dürfte, Pascal erlaubt aber auch weitere Dimensionen darüber hinaus. Bei einem zweidimensionalen Array kann zum Beispiel in Gedanken der erste Bereich für eine Zeile und der zweite Bereich für eine Spalte in dieser Zeile stehen.

Das einfachste sind wiederum mehrdimensionale statische Arrays mit festen Indexbereichen. Die einzelnen Bereiche werden mit Kommata voneinander getrennt.

var
  a1: array[1..10, 0..5] of Byte;          // zweidimensional, 10 "Zeilen" á 6 "Spalten"
  a2: array[1..10, 1..10, 1..10] of Byte;  // dreidimensional, 10 Zeilen á 10 Spalten á 10 Felder in die Tiefe


Auch die Auswertung der gespeicherten Daten erfolgt über komma-getrennte Indizes. Alternativ kann man jede Dimension in eigenen eckigen Klammern notieren:

a1[1, 0] := 15;      // gleichbedeutend mit: a1[1][0] := 15;
a2[2, 4, 8] := 0;    // gleichbedeutend mit: a2[2][4][8] := 0;


Mehrdimensionale dynamische Arrays lassen sich nach folgender Vorlage erstellen:

var a: array of array [of array...] of <Datentyp>;


Die einzelnen Unterbereiche können dabei sowohl statisch als auch dynamisch sein, man kann also Indexbereiche vorgeben. Für jeden dynamischen Unterbereich kann dann mittels SetLength() die Größe festgelegt werden.

Wir wollen nun den Vornamen und den Nachnamen auf unserer Gästeliste getrennt voneinander abspeichern. Dazu erzeugen wir zuerst ein Array mit zwei Elementen, eins für den Vornamen eins für den Nachnamen:

type
  TName = array[0..1] of string; // Index 0 = Vorname; 1 = Nachname

var
  gaeste: array of TName;


Und so einfach haben wir ein mehrdimensionales Array erzeugt. Wenn man sich dieses Array wieder als Tabelle vorstellt, hat es eine beliebige Anzahl von Zeilen (das dynamische „äußere“ Array gaeste), sowie eine Spalte für den Vornamen und eine für den Nachnamen (das statische „innere“ Array TName).

Natürlich können wir das Ganze auch in einer einzelnen Zeile deklarieren:

var
  gaeste: array of array[0..1] of string;


Nun wollen wir unsere Gästeliste erneut einlesen:

var
  index, anzahlgaeste: Integer;
  gaeste: array of array[0..1] of string;
begin
  Writeln('Bitte geben Sie die Anzahl der Gäste ein:');
  Readln(anzahlgaeste);
  SetLength(gaeste, anzahlgaeste);
  for index := 0 to High(gaeste) do
  begin
    Writeln('Bitte geben Sie den Vornamen des ', index + 1, '. Gastes ein:');
    Readln(gaeste[index, 0]);
    Writeln('Bitte geben Sie den Nachnamen des ', index + 1, '. Gastes ein:');
    Readln(gaeste[index, 1]);
  end;
  SetLength(gaeste, 0);
end.


Mit unseren fünf Gästen vom Anfang dieses Kapitels befüllt und als Tabelle dargestellt, sähe das Ganze so aus:

index gaeste[index, 0] gaeste[index, 1]
0 Axel Schweiß
1 Peter Silie
2 Jack Pot
3 Ngolo Kante
4 Manuel Neuer


Für diese Art der Datenspeicherung, wenn zwei oder mehr zusammenhängende Daten immer gemeinsam verwendet werden sollen (wie der Vor- und Nachname in unserem Beispiel), benutzt man besser Records. Wie das funktioniert, sehen wir uns als nächstes an.


Pascal: Sets Inhaltsverzeichnis Pascal: Records