Skip to content
Laviyx Learn

Try

C++ course menu

C++ 2D Arrays and Grids: Multidimensional Arrays and Vectors of Vectors

Work with tables and grids in C++: 2D C-style arrays, std::array of arrays, vectors of vectors, looping over rows and columns, row and column totals, matrix operations, and storing a grid in one flat vector.

Beginner12 min readUpdated
On this page

Many problems involve grids: a seating plan, a game board, a spreadsheet, an image made of pixels, a matrix in maths. In C++ you model a grid as an array of rows, where each row is itself an array.

2D C-style arrays#

C++
#include <iostream>

int main() {
    int grid[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12},
    };

    std::cout << grid[0][0] << ' ' << grid[1][2] << ' ' << grid[2][3] << '\n';
}
Output
1 7 12

grid[3][4] means 3 rows of 4 columns. grid[row][col] reaches one cell, with both indexes starting at 0. The sizes must be fixed at compile time.

Looping over a grid#

Use nested loops: the outer loop walks the rows, the inner loop walks the columns of the current row:

C++
#include <iostream>

int main() {
    const int rows = 3;
    const int cols = 4;
    int grid[rows][cols] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12},
    };

    for (int r = 0; r < rows; ++r) {
        for (int c = 0; c < cols; ++c) {
            std::cout << grid[r][c] << '\t';
        }
        std::cout << '\n';
    }
}
Output
1	2	3	4
5	6	7	8
9	10	11	12

std::array of std::array#

The modern fixed-size version nests std::array:

C++
#include <array>
#include <iostream>

int main() {
    std::array<std::array<char, 3>, 3> board = {{
        {'X', 'O', 'X'},
        {' ', 'X', 'O'},
        {'O', ' ', 'X'},
    }};

    for (const auto& row : board) {
        for (char cell : row) {
            std::cout << '[' << cell << ']';
        }
        std::cout << '\n';
    }

    bool diagonal = board[0][0] == 'X' && board[1][1] == 'X' && board[2][2] == 'X';
    std::cout << "X wins on the diagonal: " << std::boolalpha << diagonal << '\n';
}
Output
[X][O][X]
[ ][X][O]
[O][ ][X]
X wins on the diagonal: true

The double braces {{ ... }} are needed because std::array wraps a C-style array inside a struct.

Vectors of vectors#

When the size is only known at run time, use std::vector<std::vector<T>>:

C++
#include <iostream>
#include <vector>

int main() {
    int rows = 3;
    int cols = 5;
    std::vector<std::vector<int>> table(rows, std::vector<int>(cols, 0));

    for (int r = 0; r < rows; ++r) {
        for (int c = 0; c < cols; ++c) {
            table[r][c] = (r + 1) * (c + 1);
        }
    }

    for (const auto& row : table) {
        for (int value : row) std::cout << value << ' ';
        std::cout << '\n';
    }
}
Output
1 2 3 4 5
2 4 6 8 10
3 6 9 12 15

std::vector<std::vector<int>>(rows, std::vector<int>(cols, 0)) creates rows copies of a row with cols zeros. Each row is a separate vector, so rows can even have different lengths ("jagged" arrays), such as Pascal's triangle.

Row and column totals#

A common task is summarizing a table. Here, sales[r][c] holds sales for shop r in month c:

C++
#include <iostream>
#include <vector>

int main() {
    std::vector<std::vector<int>> sales = {
        {120, 150, 110},
        {90, 95, 130},
        {200, 180, 210},
    };

    for (std::size_t r = 0; r < sales.size(); ++r) {
        int row_total = 0;
        for (int v : sales[r]) row_total += v;
        std::cout << "Shop " << r + 1 << ": " << row_total << '\n';
    }

    for (std::size_t c = 0; c < sales[0].size(); ++c) {
        int col_total = 0;
        for (std::size_t r = 0; r < sales.size(); ++r) col_total += sales[r][c];
        std::cout << "Month " << c + 1 << ": " << col_total << '\n';
    }
}
Output
Shop 1: 380
Shop 2: 315
Shop 3: 590
Month 1: 410
Month 2: 425
Month 3: 450

For column totals, the column loop is on the outside.

Transposing a matrix#

Transposing swaps rows and columns: element [r][c] moves to [c][r]:

C++
#include <iostream>
#include <vector>

int main() {
    std::vector<std::vector<int>> m = {{1, 2, 3}, {4, 5, 6}};

    std::vector<std::vector<int>> t(m[0].size(), std::vector<int>(m.size()));
    for (std::size_t r = 0; r < m.size(); ++r) {
        for (std::size_t c = 0; c < m[0].size(); ++c) {
            t[c][r] = m[r][c];
        }
    }

    for (const auto& row : t) {
        for (int v : row) std::cout << v << ' ';
        std::cout << '\n';
    }
}
Output
1 4
2 5
3 6

One flat vector#

For large grids where performance matters, store all cells in one vector of rows * cols elements and compute the position yourself: cell (r, c) is at index r * cols + c. This keeps all data in a single block of memory, which is faster than many separate row vectors:

C++
#include <iostream>
#include <vector>

int main() {
    int rows = 2;
    int cols = 3;
    std::vector<int> cells(rows * cols, 0);

    auto at = [&](int r, int c) -> int& { return cells[r * cols + c]; };

    at(1, 2) = 7;
    at(0, 1) = 4;

    for (int r = 0; r < rows; ++r) {
        for (int c = 0; c < cols; ++c) std::cout << at(r, c) << ' ';
        std::cout << '\n';
    }
}
Output
0 4 0
0 0 7

Common mistakes#

Practice#

Practice exercise

Given a 3×3 matrix {{2, 7, 6}, {9, 5, 1}, {4, 3, 8}}, check whether it is a magic square: every row, every column and both diagonals add up to the same number. Print the result.

Show solution
C++
#include <iostream>
#include <vector>

int main() {
    std::vector<std::vector<int>> m = {{2, 7, 6}, {9, 5, 1}, {4, 3, 8}};
    int n = static_cast<int>(m.size());

    int target = 0;
    for (int v : m[0]) target += v;

    bool magic = true;
    int diag1 = 0;
    int diag2 = 0;
    for (int i = 0; i < n; ++i) {
        int row = 0;
        int col = 0;
        for (int j = 0; j < n; ++j) {
            row += m[i][j];
            col += m[j][i];
        }
        if (row != target || col != target) magic = false;
        diag1 += m[i][i];
        diag2 += m[i][n - 1 - i];
    }
    if (diag1 != target || diag2 != target) magic = false;

    std::cout << "Magic square: " << std::boolalpha << magic << " (sum " << target << ")\n";
}
Output
Magic square: true (sum 15)

Key takeaway#

Finished this lesson?