10.5 – Многомерные массивы
Элементы массива могут быть любого типа данных, включая массивы! Массив массивов называется многомерным массивом.
int array[3][5]; // 3-элементный массив из 5-элементных массивов
Поскольку здесь у нас есть 2 индекса, это двумерный массив.
В двумерном массиве удобно рассматривать первый (левый) индекс как строку, а второй (правый) индекс как столбец. Это называется строковым порядком. Концептуально представленный выше двумерный массив имеет следующую структуру:
[0][0] [0][1] [0][2] [0][3] [0][4] // строка 0
[1][0] [1][1] [1][2] [1][3] [1][4] // строка 1
[2][0] [2][1] [2][2] [2][3] [2][4] // строка 2
Чтобы получить доступ к элементам двумерного массива, просто используйте два индекса:
array[2][3] = 7;
Инициализация двумерных массивов
Для инициализации двумерного массива проще всего использовать вложенные фигурные скобки, где каждый набор чисел представляет собой строку:
int array[3][5]
{
{ 1, 2, 3, 4, 5 }, // строка 0
{ 6, 7, 8, 9, 10 }, // строка 1
{ 11, 12, 13, 14, 15 } // строка 2
};
Хотя некоторые компиляторы позволяют вам опускать внутренние фигурные скобки, мы настоятельно рекомендуем вам включать их в любом случае, как для удобства чтения, так и из-за того, как C++ заменяет отсутствующие инициализаторы на 0.
int array[3][5]
{
{ 1, 2 }, // строка 0 = 1, 2, 0, 0, 0
{ 6, 7, 8 }, // строка 1 = 6, 7, 8, 0, 0
{ 11, 12, 13, 14 } // строка 2 = 11, 12, 13, 14, 0
};
Двумерные массивы со списками инициализаторов могут опускать (только) крайнюю левую спецификацию длины:
int array[][5]
{
{ 1, 2, 3, 4, 5 },
{ 6, 7, 8, 9, 10 },
{ 11, 12, 13, 14, 15 }
};
Компилятор может вычислить, чему равна длина массива. Однако следующее не допускается:
int array[][]
{
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 }
};
Как и обычные массивы, многомерные массивы могут быть инициализированы значением 0 следующим образом:
int array[3][5]{};
Доступ к элементам в двумерном массиве
Для доступа ко всем элементам двумерного массива требуются два цикла: один для строки и один для столбца. Поскольку доступ в двумерных массивах обычно осуществляется построчно, индекс строки обычно используется в качестве внешнего цикла.
for (int row{ 0 }; row < numRows; ++row) // пройти по строкам в массиве
{
for (int col{ 0 }; col < numCols; ++col) // пройти по каждому элементу в строке
{
std::cout << array[row][col];
}
}
В C++11 циклы for-each также могут использоваться с многомерными массивами. Цикл for-each мы подробно рассмотрим позже.
Многомерные массивы больше двух измерений
Многомерные массивы могут быть больше двух измерений. Вот объявление трехмерного массива:
int array[5][4][3];
Трехмерные массивы сложно инициализировать каким-либо интуитивно понятным способом с использованием списков инициализаторов, поэтому обычно лучше инициализировать массив значением 0, а затем явно присвоить значения с помощью вложенных циклов.
Доступ к элементу трехмерного массива аналогичен двумерному случаю:
std::cout << array[3][1][2];
Пример двумерного массива
Давайте посмотрим на практический пример двумерного массива:
#include <iostream>
int main()
{
constexpr int numRows{ 10 };
constexpr int numCols{ 10 };
// Объявление массива 10x10
int product[numRows][numCols]{};
// Рассчитываем таблицу умножения
for (int row{ 1 }; row < numRows; ++row)
{
for (int col{ 1 }; col < numCols; ++col)
{
product[row][col] = row * col;
}
}
// Распечатываем таблицу
for (int row{ 1 }; row < numRows; ++row)
{
for (int col{ 1 }; col < numCols; ++col)
{
std::cout << product[row][col] << '\t';
}
std::cout << '\n';
}
return 0;
}
Эта программа вычисляет и распечатывает таблицу умножения для всех значений от 1 до 9 (включительно). Обратите внимание, что при печати таблицы циклы for
начинаются с 1 вместо 0. Это позволяет не печатать столбец 0 и строку 0, которые будут просто набором нулей! Вот результат:
1 2 3 4 5 6 7 8 9
2 4 6 8 10 12 14 16 18
3 6 9 12 15 18 21 24 27
4 8 12 16 20 24 28 32 36
5 10 15 20 25 30 35 40 45
6 12 18 24 30 36 42 48 54
7 14 21 28 35 42 49 56 63
8 16 24 32 40 48 56 64 72
9 18 27 36 45 54 63 72 81
Двумерные массивы обычно используются в играх с тайловой (плиточной) графикой, где каждый элемент массива представляет один тайл. Они также используются в трехмерной компьютерной графике (в качестве матриц) для поворота, масштабирования и отражения фигур.