zippo
не является указателем. Это массив значений массива. zippo
и zippo[i]
для i
в 0..4 в некоторых случаях могут «затухать» к указателю (в частности, в контекстах значений). Попробуйте напечатать sizeof zippo
для примера использования zippo
в не значащем контексте. В этом случае sizeof
сообщит о размере массива, а не о размере указателя.
Имя массива в значениях распадается на указатель на его первый элемент. Таким образом, в контексте значения zippo
совпадает с &zippo[0]
и, следовательно, имеет тип «указатель на массив [2] из int
»; *zippo
, в контексте значения совпадает с &zippo[0][0]
, то есть "указатель на int
". Они имеют одинаковое значение, но разные типы.
Я рекомендую прочитать Массивы и указатели для ответа на ваш второй вопрос. Указатели имеют одинаковую «ценность», но указывают на разное количество места. Попробуйте напечатать zippo+1
и *zippo+1
, чтобы увидеть это более четко:
#include <stdio.h>
int main(void)
{
int zippo[4][2] = { {2,4}, {6,8}, {1,3}, {5,7} };
printf("%lu\n", (unsigned long) (sizeof zippo));
printf("%p\n", (void *)(zippo+1));
printf("%p\n", (void *)(*zippo+1));
return 0;
}
Для моего бега он печатает:
32
0xbffede7c
0xbffede78
Скажите, что на моей машине sizeof(int)
равно 4, а второй и третий указатели не равны по значению (как и ожидалось).
Кроме того, спецификатор формата "%p"
требует void *
в *printf()
функциях, поэтому вы должны приводить ваши указатели к void *
в ваших printf()
вызовах (printf()
- это функция с переменным числом, поэтому компилятор может ' здесь вам не нужно выполнять автоматическое преобразование).
Редактировать : Когда я говорю, что массив «распадается» на указатель, я имею в виду, что имя массива в контексте значения эквивалентно указателю. Таким образом, если у меня есть T pt[100];
для некоторого типа T
, то имя pt
имеет тип T *
в контекстах значений. Для sizeof
и унарных &
операторов имя pt
не сводится к указателю. Но вы можете сделать T *p = pt;
- это совершенно правильно, потому что в этом контексте pt
имеет тип T *
.
Обратите внимание, что этот "распад" происходит только один раз. Итак, скажем, у нас есть:
int zippo[4][2] = { {2,4}, {6,8}, {1,3}, {5,7} };
Затем zippo
в контексте значения распадается на указатель типа: указатель на массив [2] из int
. В коде:
int (*p1)[2] = zippo;
действителен, тогда как
int **p2 = zippo;
вызовет предупреждение о «несовместимом назначении указателя».
С zippo
, как указано выше,
int (*p0)[4][2] = &zippo;
int (*p1)[2] = zippo;
int *p2 = zippo[0];
все действительны. Они должны печатать одно и то же значение при печати с использованием printf("%p\n", (void *)name);
, но указатели отличаются тем, что они указывают на всю матрицу, строку и одно целое число соответственно.