/** Definition von integrierten mehrdimensionalen C++ Arrays
 * (m x n)-Matrix: Eine Matrix mit m Zeilen und n Spalten
 * hier speziell eine (3 x 5)-Matrix A und eine (5 x 3)-Matrix B
 * Ausgabe mit cout
 **/
#include <iostream>                     // Ein- und Ausgabebibliothek
#include <iomanip>                      // Für Formatierungen (z.B. setw)
using namespace std;                    // Benutze den Namensraum std

int main(){                             // Hauptfunktion
    const int m = 3;
    const int n = 5;
    int A[m][n] = { { 1, 2, 3, 4, 5},
                    {21,22,23,24,25},
                    {51,52,53,54,55} }; // Definition eines (3x5)-Integer-Arrays ((3x5)-Matrix)
    int B[n][m] = { { 1, 2, 3},
                    { 4, 5, 6},
                    { 7, 8, 9},
                    {10,11,12},
                    {13,14,15} };       // Definition eines (5x3)-Integer-Arrays ((5x3)-Matrix)

    int* zeiger_A = &A[0][0];           // Definition des Zeigers auf das Integer-Array A

    constexpr int anz_elem_A = sizeof(A)/sizeof(A[0][0]); // Gesamte Anzahl der Elemente im Array A
    constexpr int dim_m = sizeof(A)/sizeof(A[0]);         // Dimension m des Arrays (Anzahl der Zeilen der Matrix A)
    constexpr int dim_n = sizeof(A[0])/sizeof(A[0][0]);   // Dimension n des Arrays (Anzahl der Spalten der Matrix A)

    cout << "Matrix A: \n";
    for(int i=0; i < m; ++i){                  // Anfang Schleife 1 (Zeilen der Matrix)
        cout << "| ";
        for(int j=0; j < n; ++j){              // Anfang Schleife 2 (Spalten der Matrix)
            cout << setw(3) << A[i][j] << " "; // Ausgabe des Matrixwertes A_{ij}
        }                                      // Ende der 2.Schleife
        cout << "| \n";
    }                                          // Ende der 1.Schleife

    cout << "\nMatrix B: \n";
    for(int i=0; i < n; ++i){                  // Anfang Schleife 1 (Zeilen der Matrix)
        cout << "| ";
        for(int j=0; j < m; ++j){              // Anfang Schleife 2 (Spalten der Matrix)
            cout << setw(3) << B[i][j] << " "; // Ausgabe des Matrixwertes B_{ij}
        }                                      // Ende der 2.Schleife
        cout << "| \n";
    }                                          // Ende der 1.Schleife

    cout << "\nDie Adresse des mehrdimensionalen Arrays A entspricht der Referenz seines ersten Elementes:\n";
    cout << "&A[0][0] = " << &A[0][0] << " , A[0] = " << (void*)A[0] << " und zeiger_A = " << zeiger_A << "\n\n";
    cout << "Der Ausdruck A[i] ist der Zeiger auf die i-te Zeile der Matrix A:\n";
    cout << "A[0] = " << (void*)A[0] << " , A[1] = " << (void*)A[1] << " und A[2] = " << (void*)A[2] << "\n\n";
    cout << "Die gesamte Anzahl der Elemente im Array A ist " << anz_elem_A << "\n\n";
    cout << "Das Array A entspricht einer (m x n)-Matrix mit m = " << dim_m << " und n = " << dim_n << "\n\n";

    cout << "Navigieren in Arrays:\n";
    cout << "Der Zugriff auf ein Element des Arrays kann entweder ... \n";
    cout << "... durch die Angabe des Matrix-Indexes erfolgen A[2][3] = " << A[2][3] << "\n";
    cout << "... oder durch den dereferenzierten Wert seiner Zeigerposition im Array erfolgen *(A[i] + j): z.B. *(A[2] + 3) = " << *(A[2] + 3) << "\n";
    cout << "    dies ist gleichbedeutend mit *(zeiger_A + i*n + j): z.B. *(zeiger_A + 2*5 + 3) = " << *(zeiger_A + 2*5 + 3) << "\n";
    cout << "    bzw. gleichbedeutend mit zeiger_A[ i*n + j]: z.B. zeiger_A[ 2*5 + 3] = " << zeiger_A[2*5 + 3] << "\n";
}
