Hành vi bạn tìm thấy thực sự là một mụn cóc lớn trong ngôn ngữ C. Bất cứ khi nào bạn khai báo một hàm có tham số mảng, trình biên dịch sẽ bỏ qua bạn và thay đổi tham số thành con trỏ. Vì vậy, tất cả các khai báo này đều hoạt động giống như khai báo đầu tiên:
void func(int *a)
void func(int a[])
void func(int a
typedef int array_plz[5];
void func(array_plz a)
a sẽ là một con trỏ tới int trong cả bốn trường hợp. Nếu bạn chuyển một mảng cho func, nó sẽ ngay lập tức phân rã thành một con trỏ tới phần tử đầu tiên của nó. (Trên hệ thống 64 bit, con trỏ 64 bit lớn gấp đôi so với int 32 bit, vì vậy tỷ lệ sizeof của bạn trả về 2)
Mục đích duy nhất của quy tắc này là duy trì khả năng tương thích ngược với các trình biên dịch lịch sử không hỗ trợ chuyển các giá trị tổng hợp làm đối số hàm.
Điều này không có nghĩa là không thể truyền một mảng cho một hàm. Bạn có thể giải quyết vấn đề này bằng cách nhúng mảng vào một cấu trúc (về cơ bản đây là mục đích của std :: array của 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 */
}
hoặc bằng cách chuyển một con trỏ đến mảng:
void func(const int (*a)[5])
{
printf("%zd\n", sizeof(*a)/sizeof((*a)[0])); /* prints 5 */
}
Trong trường hợp kích thước mảng không phải là hằng số thời gian biên dịch, bạn có thể sử dụng kỹ thuật con trỏ đến mảng với mảng có độ dài thay đổi C99:
void func(int n, const int (*a)[n])
{
printf("%zd\n", sizeof(*a)/sizeof((*a)[0])); /* prints n */
}