Обнаруженное вами поведение на самом деле является большой бородавкой на языке C. Каждый раз, когда вы объявляете функцию, которая принимает параметр массива, компилятор игнорирует вас и изменяет параметр на указатель. Итак, все эти объявления ведут себя как первое:
void func(int *a)
void func(int a[])
void func(int a
typedef int array_plz[5];
void func(array_plz a)
a будет указателем на int во всех четырех случаях. Если вы передадите массив в func, он немедленно превратится в указатель на свой первый элемент. (В 64-битной системе 64-битный указатель вдвое больше 32-битного int, поэтому ваше соотношение sizeof возвращает 2.)
Единственная цель этого правила - поддерживать обратную совместимость с прошлыми компиляторами, которые не поддерживали передачу агрегированных значений в качестве аргументов функции.
Это не означает, что невозможно передать массив функции. Вы можете обойти эту бородавку, встроив массив в структуру (в основном это цель std :: array в C ++ 11):
struct array_rly {
int a[5];
};
void func(struct array_rly a)
{
printf("%zd\n", sizeof(a.a)/sizeof(a.a[0])); /* prints 5 */
}
или передав указатель на массив:
void func(const int (*a)[5])
{
printf("%zd\n", sizeof(*a)/sizeof((*a)[0])); /* prints 5 */
}
Если размер массива не является константой времени компиляции, вы можете использовать технику указателя на массив с массивами переменной длины C99:
void func(int n, const int (*a)[n])
{
printf("%zd\n", sizeof(*a)/sizeof((*a)[0])); /* prints n */
}