Как уже отмечали другие, int (*p)[10]
объявляет p
как указатель на массив из 10 элементов int
, тогда как int *p[10]
объявляет p
как массив из 10 элементов указателя на int
,
В C объявления строятся вокруг типов выражений , а не объектов. Идея состоит в том, что форма объявления должна соответствовать форме выражения, как оно используется в коде.
Предположим, что p
- это массив указателей на int
(второй случай). Чтобы получить доступ к определенному целочисленному значению, вы должны добавить в массив и разыменовать результат, как в
x = *p[i];
Операторы постфикса, такие как []
и ()
, имеют более высокий приоритет, чем унарные операторы, такие как *
, поэтому приведенный выше оператор анализируется как *(p[i])
(IOW, *
применяется к выражению p[i]
) ,
Тип выражения *p[i]
равен int
, поэтому соответствующее объявление p
равно int *p[10];
.
Теперь давайте предположим, что p
- указатель на массив int (первый случай). Чтобы получить доступ к конкретному целочисленному значению, вы должны разыменовать указатель, а затем добавить результат, как в
x = (*p)[i];
Опять же, поскольку []
имеет более высокий приоритет, чем *
, нам нужно использовать круглые скобки, чтобы явно связать *
с p
, а не p[i]
. Тип выражения (*p)[i]
равен int
, поэтому объявление p
равно int (*p)[10];
.