Đầu tiên, một số tiêu chuẩn :
6.7.5.3 Bộ khai báo hàm (bao gồm cả nguyên mẫu)
...
7 Khai báo một tham số là '' mảng kiểu '' sẽ được điều chỉnh thành '' con trỏ đủ điều kiện để
loại '', trong đó các định nghĩa kiểu (nếu có) là những giá trị được chỉ định trong [
và ]
của dẫn xuất kiểu mảng. Nếu từ khóa static
cũng xuất hiện trong [
và ]
của dẫn xuất kiểu mảng, thì đối với mỗi lệnh gọi hàm, giá trị của đối số thực tế tương ứng sẽ cung cấp quyền truy cập vào phần tử đầu tiên của một mảng có ít nhất bao nhiêu phần tử như được chỉ định bởi kích thước biểu hiện.
Vì vậy, trong ngắn hạn, bất kỳ tham số hàm nào được khai báo T a[]
hoặc T a[N]
được coi như thể nó đã được khai báo T *a
.
Vì vậy, tại sao các tham số mảng được xử lý như thể chúng được khai báo dưới dạng con trỏ? Đây là lý do tại sao:
6.3.2.1 Giá trị, mảng và ký hiệu hàm
...
3 Ngoại trừ khi nó là toán hạng của sizeof
toán tử hoặc toán &
tử một ngôi, hoặc là một chuỗi ký tự được sử dụng để khởi tạo một mảng, một biểu thức có kiểu '' mảng kiểu ' 'được chuyển đổi thành một biểu thức có kiểu' 'con trỏ để loại ' 'trỏ đến phần tử ban đầu của đối tượng mảng và không phải là một giá trị. Nếu đối tượng mảng có lớp lưu trữ đăng ký, hành vi là không xác định.
Cho đoạn mã sau:
int main(void)
{
int arr[10];
foo(arr);
...
}
Trong lệnh gọi tới foo
, biểu thức mảng arr
không phải là toán hạng của một trong hai sizeof
hoặc &
, vì vậy kiểu của nó được chuyển đổi ngầm định từ "mảng 10 phần tử của int
" thành "con trỏ tới int
" theo 6.2.3.1/3. Do đó, foo
sẽ nhận một giá trị con trỏ, thay vì một giá trị mảng.
Vì 6.7.5.3/7, bạn có thể viết foo
là
void foo(int a[]) // or int a[10]
{
...
}
nhưng nó sẽ được hiểu là
void foo(int *a)
{
...
}
Như vậy, hai hình thức giống hệt nhau.
Câu cuối cùng trong 6.7.5.3/7 được giới thiệu với C99 và về cơ bản có nghĩa là nếu bạn có một khai báo tham số như
void foo(int a[static 10])
{
...
}
tham số thực tế tương ứng với a
phải là một mảng có ít nhất 10 phần tử.