Я попробовал следующее объяснение, но не уверен, является ли это «правильным» объяснением.
blockquote>Не совсем, но он несколько близок.
blockquote>
t
содержит адресA[0]
, но посколькуA
является массивом, аA[0]
является указателем на массив
A[0]
является массивом , в частности, его тип -int[4]
.(который является «не совсем» указателем), C не выделяет память для указателя
blockquote>A
илиA[0]
специально НЕОБХОДИМО другие переменные указателя.Массивы и указатели представляют собой принципиально разные типы объектов. Не путайте их.
Тот факт, что в большинстве случаев выражение типа
array of T
преобразуется в значение типаpointer to T
(указывающее на первый элемент массива), несомненно, способствует путанице, но нельзя забывать, что это преобразование . В частности, для многомерных массивов или массивов массивов тип элемента массива сам по себе является типом массива, поэтому результат преобразования является указателем на массив.It выделяет память только для массива в целом. Таким образом, адрес
blockquote>A[0]
иA[0]
(который является адресомA[0][0]
), по сути, один и тот же,Нет, они существенно отличаются друг от друга, один -
A[0]
- это массив,int[4]
, другой -&A[0]
- указатель на массив из четырехint
,int(*)[4]
. Также&A[0][0]
.Но когда
A[0]
преобразуется в указатель на его первый элемент,&A[0][0]
, результирующий адрес обычно совпадает с адресомA[0]
(обычно, a указатель на объект содержит адрес байта с наименьшим адресом, принадлежащим этому объекту, и посколькуA[0]
принадлежит (является частью) объектаA
, тот, у которого самый младший адрес, первый байт, который является частьюA[0]
является первым байтом, который является частьюA
).Итак,
&A[0]
и&A[0][0]
обычно имеют одно и то же представление, но одно -int(*)[4]
, другое - [int*
.оба принадлежат под одной крышей и не являются «отдельными» сущностями. В результате
blockquote>t
в свою очередь косвенно удерживает адресA[0][0]
и*t
, дает значениеA[0][0]
, которое равно 1.Эта часть, кроме несоответствие типа, которое делает разыменование
t
неопределенным поведением более или менее правильным. Формально неопределенное поведение допускает что-либо.На практике, если
sizeof(int) == sizeof(int*)
, разыменованиеt
интерпретируетint
1, который являетсяA[0][0]
в качестве адреса, и если вы печатаете это какint
(еще одно неопределенное поведение), вы получите1
. Еслиsizeof(int*) == 2*sizeof(int)
, как это обычно бывает в 64-битных системах, разыменованиеt
обычно интерпретирует дваint
sA[0][0]
иA[0][1]
вместе как адрес -0x200000001
или0x100000002
в зависимости от того, .