for (const auto &row : ia) //
for (auto col : row) //
cout << col << endl;
Этому циклу запись в элементы не нужна, но все же управляющая переменная внешнего цикла определена как ссылка. Это сделано для того, чтобы избежать преобразования обычного массива в указатель (см. раздел 3.5.3). Если пренебречь ссылкой и написать эти циклы так, то компиляция потерпит неудачу:
for (auto row : ia)
for (auto col : row)
Как и прежде, первый цикл for
перебирает элементы массива ia
, являющиеся массивами по 4 элемента. Поскольку row
не ссылка, при его инициализации компилятор преобразует каждый элемент массива (как и любой другой объект типа массива) в указатель на первый элемент этого массива. В результате типом row
в этом цикле будет int*
. Внутренний цикл for
некорректен. Несмотря на намерения разработчика, этот цикл пытается перебрать указатель типа int*
.
for
, управляющие переменные всех циклов, кроме самого внутреннего, должны быть ссылками.
Подобно любым другим массивам, имя многомерного массива автоматически преобразуется в указатель на первый его элемент.
Поскольку многомерный массив в действительности является массивом массивов, тип указателя, в который преобразуется массив, является типом первого внутреннего массива.
int ia[3][4]; //
//
int (*p)[4] = ia; //
p = &ia[2]; //
Применяя стратегию из раздела 3.5.1, начнем рассмотрение с части (*p)
, гласящей, что p
— указатель. Глядя вправо, замечаем, что объект, на который указывает указатель p
, имеет размер 4 элемента, а глядя влево, видим, что типом элемента является int
. Следовательно, p
— это указатель на массив из четырех целых чисел.
int *ip[4]; //
int (*ip)[4]; //
auto
и decltype
(см. раздел 2.5.2).
//
//
//
for (auto p = ia; p != ia + 3; ++p) {
//
//
for (auto q = *p; q != *p + 4; ++q)
cout << *q << ' '; cout << endl;
}
Внешний цикл for
начинается с инициализации указателя p
адресом первого массива в массиве ia
. Этот цикл продолжается, пока не будут обработаны все три ряда массива ia
. Инкремент ++p
перемещает указатель p
на следующий ряд (т.е. следующий элемент) массива ia
.
Внутренний цикл for
выводит значения внутренних массивов. Он начинается с создания указателя q
на первый элемент в массиве, на который указывает указатель p
. Результатом *p
будет массив из четырех целых чисел. Как обычно, при использовании имени массива оно автоматически преобразуется в указатель на его первый элемент. Внутренний цикл for
выполняется до тех пор, пока не будет обработан каждый элемент во внутреннем массиве. Чтобы получить указатель на элемент сразу за концом внутреннего массива, мы снова обращаемся к значению указателя p, чтобы получить указатель на первый элемент в этом массиве. Затем добавляем к нему 4, чтобы обработать четыре элемента в каждом внутреннем массиве.
Конечно, используя библиотечные функции begin()
и end()
(см. раздел 3.5.3), этот цикл можно существенно упростить:
//
for (auto p = begin(ia); p != end(ia); ++p) {
//
for (auto q = begin(*p); q != end(*p); ++q)