Lý
Hãy kiểm tra chức năng gọi vì vấn đề này là độc đáo có thể nhìn thấy ở đó: Tại sao các mảng không chỉ đơn giản thông qua chức năng như mảng, bởi giá trị, như một bản sao?
Có một lý do hoàn toàn thực dụng đầu tiên: Mảng có thể lớn; nó có thể không được khuyến khích để vượt qua chúng theo giá trị bởi vì họ có thể vượt quá kích thước ngăn xếp, đặc biệt là trong những năm 1970. Các trình biên dịch đầu tiên được viết trên PDP-7 với RAM 9 kB.
Ngoài ra còn có một lý do kỹ thuật khác bắt nguồn từ ngôn ngữ. Sẽ rất khó để tạo mã cho một cuộc gọi hàm với các đối số có kích thước không được biết tại thời gian biên dịch. Đối với tất cả các mảng, bao gồm các mảng độ dài biến đổi trong C hiện đại, chỉ cần các địa chỉ được đặt trên ngăn xếp cuộc gọi. Kích thước của một địa chỉ là tất nhiên được biết đến nhiều. Ngay cả các ngôn ngữ với các loại mảng phức tạp mang thông tin kích thước thời gian chạy không vượt qua các đối tượng thích hợp trên ngăn xếp. Những ngôn ngữ này thường vượt qua "xử lý" xung quanh, đó là những gì C đã thực hiện hiệu quả, quá, trong 40 năm. Xem Jon Skeet here và một lời giải thích minh họa ông tham khảo (sic) here.
Bây giờ, một ngôn ngữ có thể làm cho nó trở thành một yêu cầu mà một mảng luôn có một kiểu hoàn chỉnh; tức là bất cứ khi nào nó được sử dụng, việc khai báo hoàn chỉnh của nó bao gồm cả kích thước phải được hiển thị. Đây là, sau khi tất cả, những gì C yêu cầu từ các cấu trúc (khi chúng được truy cập). Do đó, các cấu trúc có thể được truyền cho các hàm theo giá trị. Yêu cầu loại hoàn chỉnh cho mảng cũng sẽ làm cho các cuộc gọi chức năng dễ dàng compilable và obviate sự cần thiết phải vượt qua đối số chiều dài bổ sung: sizeof()
vẫn sẽ làm việc như mong đợi bên trong callee. Nhưng hãy tưởng tượng điều đó có nghĩa là gì. Nếu kích thước thật sự là một phần của kiểu lập luận của mảng, chúng ta sẽ cần một chức năng riêng biệt cho mỗi kích thước mảng:
// for user input.
int average_Ten(int arr[10]);
// for my new Hasselblad.
int average_ThreeTrillionThreehundredninetythreeBillionNinehundredtwentyeightMillionEighthundredsixthousandfourhundred(int arr[16544*12400]);
// ...
Trong thực tế nó sẽ là hoàn toàn tương đương với cấu trúc trôi qua, mà khác nhau về loại nếu các yếu tố của họ khác nhau (nói, một cấu trúc với 10 phần tử int và một với 16544 * 12400). Rõ ràng là mảng cần linh hoạt hơn. Ví dụ, như đã chứng minh một cách không thể cung cấp một cách hợp lý các chức năng thư viện có thể sử dụng chung có tham số mảng.
"Câu hỏi hóc búa mạnh mẽ" này, trên thực tế, điều xảy ra trong C++ khi một hàm tham chiếu đến một mảng; đó cũng là lý do tại sao không ai làm điều đó, ít nhất là không rõ ràng. Nó hoàn toàn bất tiện đến mức vô ích ngoại trừ trường hợp nhắm mục tiêu sử dụng cụ thể, và trong mã chung: C++ mẫu cung cấp tính linh hoạt thời gian biên dịch mà không có sẵn trong C.
Nếu, trong C hiện tại, thực sự mảng kích thước được biết đến nên được truyền theo giá trị luôn luôn có khả năng quấn chúng trong một cấu trúc. Tôi nhớ rằng một số tiêu đề liên quan đến IP trên Solaris xác định cấu trúc gia đình địa chỉ với mảng trong chúng, cho phép sao chép chúng xung quanh.Bởi vì bố trí byte của cấu trúc đã được cố định và đã biết, điều đó có ý nghĩa.
Đối với một số nền, cũng thú vị khi đọc Sự phát triển ngôn ngữ C của Dennis Ritchie về nguồn gốc của C. C tiền thân BCPL không có bất kỳ mảng nào; bộ nhớ chỉ là bộ nhớ tuyến tính thuần nhất với con trỏ vào nó.
Nó tiết kiệm được rất nhiều bản sao (không cần thiết). C được thiết kế cho tốc độ, không an toàn. – Kninnug
Vì sao chép các mảng được truyền dưới dạng đối số sẽ tốn kém và không cần thiết hầu hết thời gian. Ngoài ra, C ban đầu không hỗ trợ các cấu trúc truyền như các đối số hàm, do đó không có lựa chọn thiết kế rõ ràng nào để tạo các mảng khác với các cấu trúc. –
@Kninnug Người ta có thể, tất nhiên, vẫn vượt qua địa chỉ nếu muốn, như với bất cứ điều gì khác. –