В типах параметров функции массивы неявно настраиваются на указатель, к которому они будут распадаться.
Таким образом, эти пары объявлений функций, например, совместимы:
void foo(int a[]);
void foo(int *a); //compatible declaration
void bar(int a[][2][3]);
void bar(int (*a)[2][3]); //compatible declaration
Деннис Ритч ie (автор языка) объясняет это запутанное правило в https://www.bell-labs.com/usr/dmr/www/chist.html
Более того, некоторые правила, разработанные для облегчения ранних переходов, привели к дальнейшей путанице. Например, пустые квадратные скобки в объявлении функции
int f (a) int a []; {...} живое ископаемое, остаток от способа объявления указателя НБ; a, только в этом особом случае, интерпретируется в C как указатель. Нотация сохранилась частично ради совместимости, частично благодаря рационализации, которая позволила бы программистам сообщать своим читателям намерение передать указатель fa, сгенерированный из массива, а не ссылку на одно целое число. К сожалению, это сбивает с толку ученика и предупреждает читателя.
(Примечание. В Chist. html используется определение функции в стиле K & R. Прототипом эквивалента приведенного выше определения функции будет int f( int a[]){ ... }
.)
Короче говоря, правило существует главным образом для облегчения перехода от B к C и позволяет программисту сигнализировать читателю, что ожидается указатель на первый элемент массива, а не просто указатель на отдельный элемент (и без необходимости использовать комментарий).
Параметры с типом функции также настраиваются на указатели аналогичным образом.
void takeFuncPtr(void Func(void));
void takeFuncPtr(void (*Func)(void)); //compatible declaration
Возможно, более глубокий вопрос заключается в том, «почему массивы распадаются на указатели в C»? Связанный документ также дает ответ на этот вопрос:
... Эта семантика представляет собой простой переход от B, и я экспериментировал с ними в течение нескольких месяцев. Проблемы стали очевидны, когда я попытался расширить нотацию типов, особенно для добавления структурированных (записей) типов. Кажется, структуры должны интуитивно отображаться в памяти на машине, но в структуре, содержащей массив, не было хорошего места для хранения sh указателя, содержащего основание массива, или какого-либо удобного способа размещения чтобы оно было инициализировано. Например, записи каталога ранних систем Unix могут быть описаны в C как
struct {int inumber; имя персонажа [14]; };
Я хотел, чтобы структура не просто характеризовала абстрактный объект, но и описывала набор битов, которые могут быть прочитаны из каталога. Где компилятор может скрыть указатель на имя, требуемое семантикой? Даже если бы структуры рассматривались более абстрактно, а пространство для указателей могло бы быть каким-то образом скрыто, как я мог бы решить техническую проблему правильной инициализации этих указателей при выделении сложного объекта, возможно, такого, который указывал структуры, содержащие массивы, содержащие структуры на произвольную глубину? Решение представляет собой решающий скачок в эволюционной цепочке между типизированным BCPL и типизированным C. Это исключило материализацию указателя в хранилище и вместо этого вызвало создание указателя, когда имя массива упоминается в выражении. Правило, которое сохраняется в сегодняшнем C, состоит в том, что значения типа массива, когда они появляются в выражениях, преобразуются в указатели на первый из объектов, составляющих массив.
...