Behnoud Nakhostin

Two Dimensional Arrays in C++

What Is a Two Dimensional Array in C++

A two dimensional array is an array accessed using two indices: arr[i][j].
The data is interpreted as rows and columns, similar to a table or matrix.

Implementation

There are multiple ways to implement a two dimensional array in C++. The main difference between them is how the data is laid out in memory. Before looking at the implementations, it is important to understand contiguous vs non‑contiguous memory layouts.

Contiguous memory (one big block)

Non‑contiguous memory (pointer to pointer)

Note: Contiguous vs non‑contiguous describes how data is stored in memory, not the syntax.

1. Static Two Dimensional Arrays

This is the simplest way to define a two dimensional array. The dimensions must be known at compile time.

#include <iostream>
using namespace std;

int main() {
    int arr[3][5];

    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 5; j++) {
            cin >> arr[i][j];
        }
    }

    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 5; j++) {
            cout << arr[i][j] << " ";
        }
        cout << "\n";
    }

    return 0;
}

Memory layout: Single contiguous block.
Advantage: Simple and easy to use.
Disadvantage: Fixed size and cannot be resized.

2. Pointer to Pointer (Dynamic Jagged Arrays)

This approach allocates an array of pointers, where each pointer represents a row.

#include <iostream>
using namespace std;

int main() {
    int n = 0, m = 0;
    cin >> n >> m;

    int** arr = new int*[n];
    for (int i = 0; i < n; i++) {
        arr[i] = new int[m];
    }

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cin >> arr[i][j];
        }
    }

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cout << arr[i][j] << " ";
        }
        cout << "\n";
    }

    for (int i = 0; i < n; i++) {
        delete[] arr[i];
    }
    delete[] arr;

    return 0;
}

Memory layout: Non‑contiguous. Each row can be stored in a different location.
Advantage: Dimensions do not need to be known at compile time. Can support jagged arrays.
Disadvantage: Slower access, possible fragmentation, and error‑prone memory management.

3. Dynamic Two Dimensional Arrays (Single Block)

Here, all elements are stored in one contiguous block. Indexing is done manually using this formula:

arr[i][j] = arr[i * number_of_cols + j]

#include <iostream>
using namespace std;

int main() {
    int n = 0, m = 0;
    cin >> n >> m;

    int* arr = new int[n * m];

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cin >> arr[i * m + j];
        }
    }

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cout << arr[i * m + j] << " ";
        }
        cout << "\n";
    }

    delete[] arr;
    return 0;
}

Memory layout: Single contiguous block.
Advantage: Dynamic size with good cache performance.
Disadvantage: Manual index calculations make the code less readable.

Conclusion

All three approaches are valid, but they solve different problems. Static arrays are best when sizes are fixed and known early. Pointer‑to‑pointer arrays trade performance for flexibility. A single dynamic block gives the best memory locality but costs readability. Understanding how memory is laid out is more important than memorizing syntax. Once that part is clear, choosing the right approach becomes straightforward.

#C++