Двумерный массив, указатели и вывод значений элементов массива в c++
Объясните, пожалуйста, почему вот в этом коде
#include <bits/stdc++.h>
using namespace std;
int main()
{
int arr[][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
for (int i = 0; i < 9; i++)
{
cout << arr[i] << '\t' << sizeof(arr[i]) << '\n';
}
}
выводятся следующие значения:
0x61fdf0 12
0x61fdfc 12
0x61fe08 12
0x61fe14 12
0x61fe20 12
0x61fe2c 12
0x61fe38 12
0x61fe44 12
0x61fe50 12
То есть почему размер адресов переменных двумерного массива равен 12 байтам, при этом разница между соседними адресами, например, 0x61fe14 и 0x61fe20 составляет 6 байтов? Откуда вообще взялись эти числа, если целые числа занимают 4 байта.
P.S. И почему вообще, если вывести arr[i] выведется именно адрес переменной? То есть, в случае одномерного массива, если есть переменная arr[i], то ее адрес - &arr[i]. Почему нельзя было адрес переменной выводить только как &arr[i][j], зачем вторая интерпретация? Заранее спасибо.
Ответы (1 шт):
Запись
int arr[][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
эквивалентна записи
int arr[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
Следовательно, arr есть одномерный массив из трёх элементов. А элементы массива arr сами являются одномерными массивами из трёх элементов типа int.
Таким образом, имеем следующий расклад:
тип arr — это int[3][3],
тип arr[i] — это int[3],
тип arr[i][j] — это int.
sizeof(arr) == 3 * sizeof(int[3]) == 3 * (3 * sizeof(int)) // == 3 * (3 * 4), если sizeof(int) == 4
То есть почему размер адресов переменных двумерного массива равен 12 байтам
Потому что arr[i] — это не адрес переменной двумерного массива, а одномерный массив из трёх элементов типа int. Оператор sizeof применённый к массиву, возвращает количество байтов, занимаемых массивом.
И почему вообще, если вывести arr[i] выведется именно адрес переменной?
Потому что нет перегруженного оператора << для вывода массива интов, но есть оператор для вывода указателей const void*. А массив может быть неявно преобразован в указатель на свой первый элемент, а указатель int* может быть неявно преобразован в const void*.
Обратите внимание, что если массив arr[i] преобразуется в указатель, то это указатель на инт: int*. В то время как адрес самого массива &arr[i] имеет тип указателя на массив из трёх элементов типа инт: int(*)[3].
при этом разница между соседними адресами, например,
0x61fe14и0x61fe20составляет 6 байтов?
Использование букв в качестве цифр в записи числа вас не смутило? ;) Префикс 0x сигнализирует о том, что числа записаны в шестнадцатеричной системе счисления. Более наглядно разницу вы увидите, посчитав разность между вторым и первым адресами:
0x61fdfc - 0x61fdf0 == 0xC == 12 (в десятичной) == sizeof(int[3]) == 3 * sizeof(int)
Наконец, так как в массиве arr всего три элемента, то и цикл должен быть от нуля до трёх:
for (int i = 0; i < 3; i++)
Если хотите вывести самые вложенные int'ы используете два цикла:
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
cout << arr[i][j] << " ";
cout << "\n";
}