Mehrdimensionale Arrays und Zeiger
2D/3D-Arrays, Row-Major-Layout und Indexberechnung per Zeigerarithmetik.
In C++ werden Arrays mit mehr als einer Dimension (z. B. Matrizen) verwendet, um Daten in Tabellen- oder Gitterform zu organisieren. Mehrdimensionale Arrays werden im Speicher fortlaufend abgelegt und können direkt mit Zeigern (Pointers) angesprochen werden. In diesem Artikel lernen wir, wie 2D- und 3D-Arrays mit Pointern zusammenhängen, wie man auf sie zugreift und wie man dynamische Matrizen erstellt.
1. Zweidimensionale (2D) Arrays
Zweidimensionale Arrays werden normalerweise als Zeilen und Spalten betrachtet. Das folgende Beispiel definiert eine Matrix mit 2 Zeilen × 3 Spalten:
#include <iostream>
using namespace std;
int main() {
int matrix[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
cout << matrix[0][1] << endl; // 2
cout << matrix[1][2] << endl; // 6
}
In diesem Beispiel steht matrix[0][1] für das Element in Zeile 0, Spalte 1.
Da C++-Arrays bei 0 beginnen, bedeutet [1][2] die 2. Zeile, 3. Spalte.
2. Speicheranordnung
C++ speichert mehrdimensionale Arrays im Speicher im row-major order. Das bedeutet, jede Zeile wird hintereinander im Speicher abgelegt:
Speicherlayout:
matrix[0][0], matrix[0][1], matrix[0][2],
matrix[1][0], matrix[1][1], matrix[1][2]
Daher kann man mit Pointer-Arithmetik auf alle Elemente zugreifen, als wäre es ein eindimensionales Array.
3. Zugriff auf 2D-Array-Elemente mit Pointern
Mehrdimensionale Arrays sind im Grunde eine Kette von Zeigern.
Zum Beispiel enthält int matrix[2][3] eine Adresse auf ein int[3]-Array.
#include <iostream>
using namespace std;
int main() {
int matrix[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
cout << *(*(matrix + 0) + 1) << endl; // 2
cout << *(*(matrix + 1) + 2) << endl; // 6
}
matrix→ zeigt auf die erste Zeile.*(matrix + 1)→ wechselt zur zweiten Zeile.*(*(matrix + 1) + 2)→ greift auf das Element in Zeile 2, Spalte 3 zu.
4. Zugriff mit Pointern in Schleifen
Man kann über die Matrixelemente mithilfe von Pointer-Arithmetik iterieren.
int matrix[2][3] = {{10,20,30},{40,50,60}};
int *ptr = &matrix[0][0];
for (int i = 0; i < 6; i++) {
cout << *(ptr + i) << " ";
}
Ausgabe:
10 20 30 40 50 60
Wie man sieht, wird ein 2D-Array als ein einzelner Speicherblock abgelegt, daher kann man mit einem einzigen Pointer auf alle Elemente zugreifen.
5. Übergabe mehrdimensionaler Arrays an Funktionen
2D-Arrays können als Parameter an Funktionen übergeben werden. In C++ muss jedoch die zweite Dimension (Anzahl der Spalten) angegeben werden.
void Drucken(int arr[][3], int zeilen) {
for (int i = 0; i < zeilen; i++) {
for (int j = 0; j < 3; j++) {
cout << arr[i][j] << " ";
}
cout << endl;
}
}
int main() {
int matrix[2][3] = {{1,2,3},{4,5,6}};
Drucken(matrix, 2);
}
Alternativ kann Pointer-Syntax verwendet werden:
void Drucken(int (*p)[3], int zeilen) {
for (int i = 0; i < zeilen; i++)
for (int j = 0; j < 3; j++)
cout << p[i][j] << " ";
}
Hier bedeutet int (*p)[3] „Pointer auf ein Array von 3 ints“.
6. Dreidimensionale (3D) Arrays
Dreidimensionale Arrays sind Sammlungen von 2D-Arrays.
Das heißt, int raum[2][3][4] besteht aus 2 Matrizen der Größe 3×4.
#include <iostream>
using namespace std;
int main() {
int raum[2][3][4] = {
{ {1,2,3,4}, {5,6,7,8}, {9,10,11,12} },
{ {13,14,15,16}, {17,18,19,20}, {21,22,23,24} }
};
cout << raum[1][2][3] << endl; // 24
}
3D-Arrays werden häufig in Grafikverarbeitung, Spiel-Engines und wissenschaftlichen Berechnungen verwendet.
7. Dynamische Erstellung einer 2D-Matrix
Um Matrizen zu erstellen, deren Größe zur Laufzeit bestimmt wird,
kann der new-Operator mit Zeiger-Arrays verwendet werden.
#include <iostream>
using namespace std;
int main() {
int zeilen = 2, spalten = 3;
int **matrix = new int*[zeilen]; // Array von Zeilen-Pointern
for (int i = 0; i < zeilen; i++)
matrix[i] = new int[spalten]; // Array für jede Zeile erstellen
// Werte zuweisen
for (int i = 0; i < zeilen; i++)
for (int j = 0; j < spalten; j++)
matrix[i][j] = (i+1)*(j+1);
// Ausgabe
for (int i = 0; i < zeilen; i++) {
for (int j = 0; j < spalten; j++)
cout << matrix[i][j] << " ";
cout << endl;
}
// Speicher freigeben
for (int i = 0; i < zeilen; i++)
delete[] matrix[i];
delete[] matrix;
}
Mit dieser Methode kann die Matrixgröße dynamisch (z. B. durch Benutzereingabe) bestimmt werden.
Aber denken Sie daran: Für jedes new[] muss ein delete[] vorhanden sein.
8. Moderne Alternative: std::vector<vector<int>>
In C++ ist die sicherste und einfachste Methode zur Erstellung einer dynamischen Matrix die Verwendung von std::vector.
#include <iostream>
#include <vector>
using namespace std;
int main() {
int zeilen = 2, spalten = 3;
vector<vector<int>> matrix(zeilen, vector<int>(spalten));
for (int i = 0; i < zeilen; i++)
for (int j = 0; j < spalten; j++)
matrix[i][j] = (i+1) + (j+1);
for (auto &zeile : matrix) {
for (int wert : zeile)
cout << wert << " ";
cout << endl;
}
}
std::vector bietet automatische Speicherverwaltung,
erfordert kein delete[] oder new und kann leicht in der Größe geändert werden.
9. TL;DR
- 2D-Arrays werden zeilenweise (row-major order) im Speicher abgelegt.
*(matrix + i) + jist äquivalent zumatrix[i][j].- In Funktionsparametern muss die zweite Dimension angegeben werden.
- 3D-Arrays sind Sammlungen von 2D-Arrays:
int raum[2][3][4]. - Dynamische Matrizen können mit
new/delete[]erstellt werden. - In modernem C++ wird
std::vector<vector<>>empfohlen. - Alle Beispiele können mit Visual Studio 2022 oder GCC 11+ kompiliert und ausgeführt werden.