Loading...

Multidimensional Arrays and Pointer Usage

2D/3D arrays, row-major layout, and indexing math with pointers in practice.

In C++, arrays that contain more than one dimension (for example, matrices) are used to organize data in a table or grid form. Multidimensional arrays are stored contiguously in memory and can be accessed directly with pointers. In this article, we will learn how 2D and 3D arrays relate to pointers, how to access them, and how to create dynamic matrices.


1. Two-Dimensional (2D) Arrays

Two-dimensional arrays are usually thought of in rows and columns. The following example defines a matrix with 2 rows × 3 columns:


#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 this example, matrix[0][1] refers to the value in row 0, column 1. Since C++ arrays are 0-based, [1][2] is actually the 2nd row, 3rd column.


2. How They Are Stored in Memory

C++ stores multidimensional arrays in memory in row-major order. That means each row is placed contiguously in memory:


Memory layout:
matrix[0][0], matrix[0][1], matrix[0][2],
matrix[1][0], matrix[1][1], matrix[1][2]

Because of this, you can access all elements using pointer arithmetic as if it were a one-dimensional array.


3. Accessing 2D Array Elements with Pointers

Multidimensional arrays are effectively a chain of pointers. For example, in int matrix[2][3], matrix holds the address of an 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. Accessing via Pointer in a Loop

You can iterate over matrix elements using pointer arithmetic.


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) << " ";
}

Output:


10 20 30 40 50 60

As you can see, since a 2D array is stored as a single contiguous block in memory, it is possible to reach all elements with a single pointer.


5. Passing Multidimensional Arrays to Functions

2D arrays can be passed to functions as parameters. However, in C++, the second dimension (the number of columns) must be specified.


void Print(int arr[][3], int rows) {
    for (int i = 0; i < rows; 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}};
    Print(matrix, 2);
}

Alternatively, pointer syntax can be used:


void Print(int (*p)[3], int rows) {
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < 3; j++)
            cout << p[i][j] << " ";
}

Here, int (*p)[3] means “a pointer to an array of 3 ints”.


6. Three-Dimensional (3D) Arrays

Three-dimensional arrays are collections of 2D arrays. That is, int space[2][3][4] is made up of 2 matrices of size 3×4.


#include <iostream>
using namespace std;

int main() {
    int space[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 << space[1][2][3] << endl; // 24
}

3D arrays are often used in graphics processing, game engines, and scientific computations.


7. Creating a Dynamic 2D Array (Matrix)

To create matrices whose size is not known at compile time, you can use the new operator together with pointer arrays.


#include <iostream>
using namespace std;

int main() {
    int rows = 2, cols = 3;
    int **matrix = new int*[rows]; // array of row pointers

    for (int i = 0; i < rows; i++)
        matrix[i] = new int[cols]; // create array for each row

    // assign values
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < cols; j++)
            matrix[i][j] = (i+1) * (j+1);

    // print
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++)
            cout << matrix[i][j] << " ";
        cout << endl;
    }

    // free memory
    for (int i = 0; i < rows; i++)
        delete[] matrix[i];
    delete[] matrix;
}

With this method, the matrix size can be determined dynamically from user input. But remember: every new[] must have a corresponding delete[].


8. Modern Alternative: std::vector<vector<int>>

In C++, the safest and easiest way to create a dynamic matrix is to use std::vector.


#include <iostream>
#include <vector>
using namespace std;

int main() {
    int rows = 2, cols = 3;
    vector<vector<int>> matrix(rows, vector<int>(cols));

    for (int i = 0; i < rows; i++)
        for (int j = 0; j < cols; j++)
            matrix[i][j] = (i+1) + (j+1);

    for (auto &row : matrix) {
        for (int value : row)
            cout << value << " ";
        cout << endl;
    }
}

std::vector provides automatic memory management, does not require delete[] or new, and can be easily resized.


9. TL;DR

  • 2D arrays are stored row by row in memory (row-major order).
  • *(matrix + i) + j is equivalent to matrix[i][j].
  • The second dimension must be specified in function parameters.
  • 3D arrays are collections of 2D arrays: int space[2][3][4].
  • Dynamic matrices can be created with new / delete[].
  • In modern C++, std::vector<vector<>> is recommended.
  • All examples can be run in Visual Studio 2022 or GCC 11+ compilers.

Related Articles