~~SLIDYSHOW~~

Eindimensionale Arrays

Definition eines Arrays

Ein eindimensionales Array wird nach dem Schema

T a[n]

definiert. Hier ist

Das Array

T a[n] 

hat die n Elemente

a[0], ..., a[n–1]

Durch die Definition eines Arrays a mit n Elementen des Datentyps T reserviert der Compiler einen zusammenhängenden Speicherbereich für n Elemente, also n*sizeof(T) Bytes. Damit der Compiler den erforderlichen Speicherplatz reservieren kann, muss die Anzahl der Arrayelemente zum Zeitpunkt der Kompilation bekannt und deshalb eine Konstanten sein. Es ist nicht möglich, die Größe eines Arrays während der Laufzeit des Programms über eine Variable festzulegen oder gar zu verändern. Der Datentyp von a ist „Array mit n Elementen des Datentyps T“ oder kurz „T[n]“ (z.B. „int[10]“). Der Datentyp Array gehört zu den sogenannten zusammengesetzten Datentypen, da ein Array aus Elementen zusammengesetzt ist.

Beispiele: Alle diese Arraydefinitionen sind zulässig. Der Datentyp des Arrays ist als Kommentar angegeben:

int a[10]; // "int[10]"
double d[20]; // "double[20]"
bool Primzahlen[30]; // "bool[30]"
long double e[40]; // "long double[40]"
 
const int MaxLines = 17;
AnsiString AS[MaxLines]; // "AnsiString[17]"

Eine nicht konstante Anzahl von Arrayelementen hat eine Fehlermeldung des Compilers zur Folge:

int M = 18;
char line[M]; //Fehler: Konstante erforderlich

Bei der Definition eines Arrays muss darauf geachtet werden, dass seine Größe im Rahmen der zulässigen Speichergrenzen liegt. Unter DOS oder 16-bit-Windows lag die Obergrenze oft bei 64 KB oder weniger, wenn nicht spezielle Speichermodelle gewählt wurden. Die Obergrenze von 2 GB für globale Definitionen unter Win32 und dem C++Builder dürfte meist keine Einschränkung darstellen. Für lokale Definitionen liegt die Voreinstellung für die Obergrenze bei 1 MB.

Beispiel: Die folgende Definition benötigt mehr als 2 GB und führt zu einem Laufzeitfehler. Der Compiler gibt aber weder eine Warnung noch eine Fehlermeldung aus:

int z[INT_MAX]; // zu groß, Laufzeitfehler

Das nächste Array benötigt mehr als 1 MB und kann global definiert werden. Eine lokale Definition führt zu einem Stack overflow, wenn man die voreingestellte Größe für den Stack nicht erhöht:

int z[300000]; // global möglich, aber nicht lokal

Die Elemente eines Arrays werden mit dem Indexoperator [] über ihren Index angesprochen: Der Index wird in eckigen Klammern nach dem Namen des Arrays angegeben und muss ein ganzzahliger Ausdruck sein. Jedes Element eines Arrays ist ein Ausdruck des Datentyps, der bei der Definition des Arrays angegeben wurde.

Beispiele: Nach den Definitionen von oben ist

a[9] ein Ausdruck des Datentyps int,
d[0] ein Ausdruck des Datentyps double,
Primzahlen[1] ein Ausdruck des Datentyps bool,
e[2] ein Ausdruck des Datentyps long double,

Um alle n Elemente eines Arrays anzusprechen, verwendet man meist eine for-Schleife, die von 0 bis n–1 läuft:

for (int i=0; i<n; i++) a[i]=i;

Da der Index ein beliebiger ganzzahliger Ausdruck sein kann, akzeptiert der Compiler mit einer int Variablen i die folgenden Ausdrücke als Indizes:

a[i], a[i*i+19], d[(a[i]+a[j])/2]

Wenn für ein mit n Elementen definiertes Array ein Index angegeben wird, der nicht im Bereich der Grenzen 0..n–1 liegt, werden Speicherbereiche angesprochen, die nicht für das Array reserviert sind. Man muss deshalb immer darauf achten, dass der Index im Bereich der Grenzen liegt, die bei der Definition des Arrays angegeben wurde.


Aufgabe

Schreibe ein Programm, welches ein Array mit 10 Elementen anlegt (Inhalt: Zahlen 10 - 19) und dieses anschließend ausgibt.


Ein Array kann nicht auf der linken Seite einer Zuweisung stehen. Deshalb kann ein Array a einem anderen Array b nicht mit dem Zuweisungsoperator zugewiesen werden, auch wenn beide denselben Datentyp haben.

Beispiel: Nach der Definition

int a[10],b[10];

wird die nächste Zuweisung vom Compiler abgelehnt:

a=b; // Fehler: L-Wert erwartet

Um sämtliche Elemente von b nach a zu übertragen, kann man z.B. alle einzeln kopieren:

for (i=0;i<10;i++) a[i]=b[i];

Mit dem Operator sizeof erhält man die Anzahl der von einem Array belegten Bytes:

sizeof(a)

Es ist in der Regel immer empfehlenswert, die Anzahl der Arrayelemente bei der Definition eines gewöhnlichen Arrays über eine symbolische Konstante anzugeben, und diese immer dann zu verwenden, wenn man das letzte Element anspricht. Falls es dann einmal notwendig sein sollte, die Größe des Arrays zu ändern, muss nur diese Konstante geändert werden.

Beispiel: Obwohl das Programmfragment

int a[10], sum=0;
...
for (int i=0; i<=9;i++) sum = sum+a[i];

seinen Zweck durchaus korrekt erfüllen kann, ist die folgende Variante meist vorteilhafter:

const int max=10;
int a[max], sum=0;
...
for (int i=0; i<max; i++) sum = sum+a[i];

Bei der ersten Variante muss das gesamte Programm nach allen Stellen durchsucht werden, an denen die Elementanzahl verwendet wird. Das kann bei einem größeren Programm recht mühsam werden, insbesondere wenn die Konstante nicht explizit verwendet wird, sondern nur ein abgeleiteter Wert (9 statt 10 in der for-Schleife).

Aber auch dann, wenn die Anzahl der Arrayelemente ganz sicher nie verändert werden muss, ist die Verwendung symbolischer Konstanten meist vorteilhaft: Mit einem aussagekräftigen Namen für die Konstante ist die Zeile

for (int i=0; i<max; i++) sum = sum+a[i];

meist leichter verständlich als

for (int i=0; i<10; i++) sum = sum+a[i];