Eine Reihe von Werten mit fester Größe
Ein Array ist ein zusammenhängender Speicherblock, der eine feste Anzahl von Werten desselben Typs enthält. Während ein einzelnes int eine Zahl speichert, speichert ein int-Array viele davon hintereinander, jede über einen ganzzahligen Index erreichbar.
Du deklarierst eines, indem du den Elementtyp, einen Namen und eine Größe in eckigen Klammern angibst. Füge eine Liste in geschweiften Klammern hinzu, um es zu füllen:
Die Indizierung beginnt bei null: Das erste Element ist scores[0], und ein Array der Größe 4 hat gültige Indizes von 0 bis 3. Die Größe muss eine Konstante zur Übersetzungszeit sein — du kannst in Standard-C++ nicht int n = readInput(); int a[n]; schreiben (das ist eine nicht portable Erweiterung). Wenn du eine zur Laufzeit bestimmte Größe brauchst, greife stattdessen zu einem vector.
Arrays initialisieren
Es gibt mehrere Möglichkeiten, ein Array zu füllen, und ein paar Abkürzungen, die man kennen sollte:
Der Kniff, den man verinnerlichen sollte: Wenn du weniger Initialisierer angibst als die Größe, werden die übrigen wertinitialisiert (null bei numerischen Typen), nicht als Müll belassen. Ein Array ohne jeden Initialisierer hingegen — int e[4]; als lokale Variable deklariert — enthält unbestimmte Werte, und sie vor der Zuweisung zu lesen ist undefiniertes Verhalten.
Über ein Array iterieren
Da die Elemente zusammenhängend gespeichert sind, durchläufst du ein Array mit einer einfachen Index-Schleife. Um in den Grenzen zu bleiben, steuere die Schleife mit der tatsächlichen Länge des Arrays statt mit einer fest codierten Zahl:
sizeof(scores) ist die gesamte Byte-Anzahl des ganzen Arrays; geteilt durch sizeof(scores[0]) (die Größe eines Elements) ergibt das die Anzahl der Elemente. Seit C++17 gibt es eine sauberere Schreibweise, std::size(scores), die sich besser liest und sich weigert zu kompilieren, wenn du ihr versehentlich einen Zeiger übergibst. Noch einfacher, wenn du nur die Werte brauchst: Eine bereichsbasierte for-Schleife erspart dir die Index-Rechnerei komplett.
Die Falle des Zugriffs außerhalb der Grenzen
C++ führt bei arr[i] keine Grenzprüfung durch. Ein Zugriff über das letzte Element hinaus wirft keine Ausnahme und warnt nicht — es liest oder schreibt einfach den Speicher, der zufällig dort liegt. Das ist der mit Abstand häufigste Array-Fehler und ein klassischer Fall von undefiniertem Verhalten:
int a[3] = {1, 2, 3};
a[3] = 99; // OOPS - valid indices are 0..2, not 3
cout << a[5]; // garbage, crash, or corruption - undefined behavior
Der Off-by-one-Fehler versteckt sich meist in einer Schleifenbedingung. i <= n statt i < n zu schreiben geht einen Schritt zu weit und greift auf arr[n] zu, das nicht existiert:
for (int i = 0; i <= n; i++) // BUG: when i == n, arr[i] is out of bounds
cout << arr[i];
Die Lösung ist die Disziplin aus dem vorigen Abschnitt: Schleife mit i < size, niemals mit <=, und berechne die Größe aus dem Array, statt ein Literal erneut zu tippen, das aus dem Takt gerät, sobald du ein Element hinzufügst.
Array-Decay: der versteckte Zeiger
Das kniffligste Array-Verhalten in C++ ist das Decay: Wenn du ein Array an eine Funktion übergibst, wird es stillschweigend in einen Zeiger auf sein erstes Element umgewandelt. Die Größeninformation geht verloren, daher misst sizeof innerhalb der Funktion den Zeiger, nicht das Array.
Beachte, dass int arr[] und int* arr als Funktionsparameter identisch sind — die Klammern sind reine Kosmetik. Da die Anzahl verloren ist, musst du die Länge selbst neben dem Array übergeben:
int sum(const int* arr, int n) {
int total = 0;
for (int i = 0; i < n; i++) total += arr[i];
return total;
}
Genau dieses Muster „übergib einen Zeiger und eine Länge und bete, dass sie zusammenpassen" ist die Reibung, die den meisten C++-Code in Richtung std::array und std::vector drängt, die ihre eigene Größe mitführen und nie zerfallen.
Ein kurzes Wort zu mehrdimensionalen Arrays
Du kannst die Klammern verschachteln, um ein Gitter zu erzeugen. Ein 2D-Array ist in Wirklichkeit ein Array von Arrays, im Speicher Zeile für Zeile abgelegt:
Indiziere es als grid[row][col]. Es gelten dieselben Vorbehalte zu Grenzen und Decay — und sie werden schlimmer, da das Übergeben eines 2D-Arrays an eine Funktion erfordert, jede Dimension außer der ersten auszuschreiben (void f(int g[][3])). Für alles, was über ein kleines, festes Gitter hinausgeht, ist ein vector von vectors deutlich weniger fehleranfällig.
Als Nächstes: Vector
Roh-Arrays sind schnell und vorhersehbar, aber ihre feste Größe, das Fehlen von Grenzsicherheit und ihr Decay-zu-Zeiger-Verhalten machen sie für alltäglichen Code unhandlich. Als Nächstes lernen wir std::vector kennen — ein größenveränderbares Array, das bei Bedarf wächst, sich seine eigene Größe merkt und sich direkt an die STL-Algorithmen anschließt; es gibt dir fast alles, was Arrays bieten, mit weit weniger Möglichkeiten, dir selbst ins Knie zu schießen.
Häufig gestellte Fragen
Wie deklariert und initialisiert man ein Array in C++?
Schreibe den Elementtyp, einen Namen und die Größe in eckigen Klammern, dann optional eine Liste in geschweiften Klammern: int scores[4] = {90, 75, 100, 60};. Du kannst die Größe weglassen, wenn du Initialisierer angibst — int scores[] = {90, 75, 100, 60}; lässt den Compiler sie für dich zählen.
Wie ermittelt man die Länge eines Arrays in C++?
Für ein echtes Array, das noch im Gültigkeitsbereich liegt, verwende std::size(arr) (C++17) oder sizeof(arr) / sizeof(arr[0]). Das funktioniert nicht mehr, sobald das Array zu einem Zeiger zerfallen ist (z. B. innerhalb einer Funktion, die int arr[] entgegengenommen hat), wo sizeof die Größe des Zeigers liefert, nicht die des Arrays.
Was passiert, wenn man in C++ außerhalb der Grenzen eines Arrays zugreift?
Das ist undefiniertes Verhalten. C++ führt bei arr[i] keine Grenzprüfung durch, daher kann das Lesen oder Schreiben über das Ende hinaus abstürzen, Müll zurückgeben oder still benachbarten Speicher beschädigen. Halte deinen Index immer im Bereich 0 bis size - 1.