Wird geladen...

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
}


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) + j ist äquivalent zu matrix[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.

Ähnliche Artikel