Điều bạn đang nói trong bài đăng của mình là hoàn toàn chính xác. Tôi muốn nói rằng mọi nhà phát triển C đều có cùng một khám phá và kết luận chính xác khi (nếu) họ đạt được trình độ thông thạo nhất định với ngôn ngữ C.
Khi các chi tiết cụ thể trong vùng ứng dụng của bạn gọi một mảng có kích thước cố định cụ thể (kích thước mảng là hằng số biên dịch), cách duy nhất để truyền một mảng như vậy đến hàm là bằng cách sử dụng con trỏ tới mảng tham số
void foo(char (*p)[10]);
(bằng ngôn ngữ C++ này cũng được thực hiện với sự tham khảo
void foo(char (&p)[10]);
).
Điều này sẽ bật kiểm tra loại cấp độ ngôn ngữ, sẽ đảm bảo rằng mảng chính xác kích thước được cung cấp dưới dạng đối số. Trong thực tế, trong nhiều trường hợp người sử dụng kỹ thuật này mặc nhiên, mà không hề nhận ra nó, ẩn kiểu mảng đằng sau một tên typedef
typedef int Vector3d[3];
void transform(Vector3d *vector);
/* equivalent to `void transform(int (*vector)[3])` */
...
Vector3d vec;
...
transform(&vec);
Lưu ý thêm rằng mã trên là bất biến với liên quan đến Vector3d
loại là một mảng hoặc một struct
. Bạn có thể chuyển định nghĩa của Vector3d
bất kỳ lúc nào từ một mảng thành struct
và ngược lại, và bạn sẽ không phải thay đổi khai báo hàm. Trong cả hai trường hợp, các hàm sẽ nhận được một đối tượng tổng hợp "bằng cách tham chiếu" (có những ngoại lệ cho điều này, nhưng trong bối cảnh của cuộc thảo luận này điều này là đúng). Tuy nhiên, bạn sẽ không thấy phương pháp này được sử dụng một cách rõ ràng quá thường xuyên, đơn giản vì quá nhiều người bị lẫn lộn bởi một cú pháp khá phức tạp và đơn giản là không đủ thoải mái với các tính năng của ngôn ngữ C để sử dụng chúng đúng cách. Vì lý do này, trong thực tế trung bình cuộc sống, đi qua một mảng như một con trỏ đến yếu tố đầu tiên của nó là một cách tiếp cận phổ biến hơn. Nó chỉ trông "đơn giản hơn". Nhưng trên thực tế, việc sử dụng con trỏ đến phần tử đầu tiên để chuyển mảng là một kỹ thuật rất thích hợp, một mẹo, phục vụ một mục đích rất cụ thể: mục đích duy nhất của nó là tạo điều kiện cho mảng đi qua của kích thước khác nhau (I Ekích thước thời gian chạy). Nếu bạn thực sự cần phải có khả năng xử lý mảng kích thước thời gian chạy, sau đó một cách thích hợp để vượt qua một mảng như vậy là bởi một con trỏ đến phần tử đầu tiên của mình với kích thước bê tông được cung cấp bởi một tham số bổ sung
void foo(char p[], unsigned plen);
Trên thực tế , trong nhiều trường hợp, nó rất hữu ích để có thể xử lý các mảng kích thước thời gian chạy, cũng góp phần vào sự phổ biến của phương thức. Nhiều nhà phát triển C chỉ đơn giản là không bao giờ gặp phải (hoặc không bao giờ nhận ra) sự cần thiết phải xử lý một mảng có kích thước cố định, do đó vẫn không biết đến kỹ thuật kích thước cố định thích hợp.
Tuy nhiên, nếu kích thước mảng là cố định, đi qua nó như một con trỏ đến một yếu tố
void foo(char p[])
là một lỗi kỹ thuật cấp lớn, mà tiếc là khá phổ biến những ngày này. Một kỹ thuật con trỏ tới mảng là một cách tiếp cận tốt hơn nhiều trong các trường hợp như vậy.
Một lý do khác có thể cản trở việc áp dụng kỹ thuật truyền mảng cố định là sự thống trị của cách tiếp cận ngây thơ để nhập mảng được phân bổ động. Ví dụ, nếu chương trình đòi hỏi mảng cố định kiểu char[10]
(như trong ví dụ của bạn), một nhà phát triển trung bình sẽ malloc
mảng như
char *p = malloc(10 * sizeof *p);
mảng này không thể được truyền cho một chức năng khai báo là
void foo(char (*p)[10]);
gây nhầm lẫn cho nhà phát triển trung bình và khiến họ từ bỏ tuyên bố tham số kích thước cố định mà không phải suy nghĩ thêm. Trong thực tế, gốc rễ của vấn đề nằm trong cách tiếp cận ngây thơ malloc
. Định dạng malloc
được hiển thị ở trên phải được dành riêng cho các mảng có kích thước thời gian chạy. Nếu kiểu mảng có thời gian biên dịch kích thước, một cách tốt hơn để malloc
nó sẽ trông như sau
char (*p)[10] = malloc(sizeof *p);
này, tất nhiên, có thể dễ dàng truyền cho trên tuyên bố foo
foo(p);
và trình biên dịch sẽ thực hiện kiểm tra kiểu thích hợp. Nhưng một lần nữa, điều này là quá khó hiểu với một nhà phát triển C không chuẩn bị, đó là lý do tại sao bạn sẽ không thấy nó quá thường xuyên trong mã trung bình hàng ngày "điển hình".
lưu ý: Kể từ C99 mảng không nhất thiết phải có kích cỡ cố định theo đề nghị của danh hiệu, '10' có thể được thay thế bằng bất kỳ biến trong phạm vi –