Если мы «рисуем» ваш массив так, как он расположен в памяти, он будет выглядеть примерно так:
+----+----+----+----+----+
| 10 | 20 | 30 | 40 | 50 |
+----+----+----+----+----+
Тогда вам нужно помнить, что массивы естественным образом распадаются на указатели на их первый элемент, то есть tab
равно &tab[0]
.И затем вам нужно помнить, что для любого массива или указателя a
и индекса i
выражение a[i]
точно равно *(a + i)
.Из этого легко сделать вывод, что tab + 4
равен &tab[4]
, то есть указателю на пятый элемент.
Так что, если мы снова нарисуем массив, но теперь с указателями:
+----+----+----+----+----+
| 10 | 20 | 30 | 40 | 50 |
+----+----+----+----+----+
^ ^
| |
&tab[0] &tab[4]
|
&tab
Если &tab[0]
равно 0x28fef8
, то &tab[4]
равно 0x28fef8 + sizeof(int) * 4
, так как оно указывает на индекс 4 массива int
, и это действительно 0x28ff08
.
Обратите внимание, что хотя &tab[0]
и &tab
указывают на одно и то же местоположение, они семантически различны.&tab[0]
является указателем на отдельные элементы и имеет тип int *
, тогда как &tab
является указателем на массив и имеет тип int (*)[5]
.
В связанной заметке,правильный формат для печати void *
указателей - "%p"
.Таким образом, ваша печать должна быть действительно
printf("%d,%p,%p. \n", *ptr-1, (void *) &tab, (void *) ptr);
Обратите внимание, что приведение к void *
действительно необходимо.