Код играет в игры зло указатель, без удачи. Вы передаете указатель типа int(*)[10]
функции, которая хочет указатель типа int**
. Указатель, который вы передаете, имеет в качестве значения «базовый адрес» массива.
Таким образом, когда вы разыменовываете int**
, он думает, что по этому адресу он получает int*
, хотя то, на что он смотрит, является int
объектом. И он записывает адрес, возвращенный с malloc
в эту ячейку памяти.
Вернувшись в главное, вы распечатываете эту ячейку. Обратите внимание, что это значение первого элемента массива, а не адрес первого элемента массива. Таким образом, выводится целочисленная интерпретация адреса, который вы написали в вызываемой функции.
То, что вы делаете, это неопределенное поведение: функция хочет int**
, поэтому вы должны дать ей int**
,
Вот как я думаю вы рассматриваете вопрос
- Вы слышите, как кто-то говорит, что имя массива является постоянным указателем на его первый элемент
- Вы берете адрес этого указателя, отбрасываете любые константы
- Вы с радостью пишете какой-то другой адрес в указатель и надеетесь, что он не потерпит крах
- Вы снова используете массив, ожидая, что он «наложит» область неинициализированной памяти, созданную malloc.
Но это представление ошибочно. Первая точка наиболее ошибочна, поскольку имя массива не является постоянным указателем. Если бы первый пункт был верным, ваш фрагмент имел бы намного больше смысла, на самом деле. Но имя массива будет генерировать значение адреса, которое ссылается на его первый элемент, когда вы используете его в выражении, за исключением очень немногих случаев (sizeof, address-of).
Поскольку это значение адреса не генерируется при использовании address-of, вместо этого вы получите указатель на этот массив (именно то, что вы написали с помощью оператора address-of). Поскольку имеет смысл, что массив и первый его элемент имеют одинаковый адрес, адрес массива совпадает с адресом его первого элемента. Так что вы на самом деле сделали запись в первый элемент, вместо записи в какой-то указатель (которого на самом деле нет).
Ответ на комментарий
Рассмотрим, что происходит, когда тип массива имеет значение на практике (из этих экспериментов). У вас есть массив, элементы которого сами являются массивами.
// array of 3 "array of 10 int"
int a[3][10];
Таким образом, используя a
в выражении, отличном от &
и sizeof
, вы получите указатель на первый элемент, int(*)[10]
. Это очень важно, потому что следующее записывает в целое число смещение 2*sizeof(int)*10
байт
a[2][0] = 1;
// (a + 2) refers to a offset by 2*sizeof(int)*10 bytes
Если a
в этом выражении даст вам int**
, то компилятор не будет знать, где он должен правильно хранить целое число 1
, потому что любая информация о размере о типе элемента теряется. Конечно, он может хранить размер где-то в памяти, но где? В массиве нет места для этого. И, кроме того, sizeof
больше не сможет дать вам результат компиляции.