您在帖子中所说的绝对正确。我想说每个 C 开发人员在(如果)达到一定的 C 语言熟练程度时都会得出完全相同的发现和完全相同的结论。
当您的应用程序区域的细节需要特定固定大小的数组(数组大小是编译时常量)时,将此类数组传递给函数的唯一正确方法是使用指向数组的指针参数
void foo(char (*p)[10]);
(在 C++ 语言中,这也是通过引用完成的
void foo(char (&p)[10]);
)。
这将启用语言级别的类型检查,这将确保提供大小完全正确的数组作为参数。事实上,在很多情况下,人们都隐含地使用了这种技术,甚至没有意识到,将数组类型隐藏在 typedef 名称后面
typedef int Vector3d[3];
void transform(Vector3d *vector);
/* equivalent to `void transform(int (*vector)[3])` */
...
Vector3d vec;
...
transform(&vec);
另外请注意,上面的代码对于Vector3d 类型是数组或struct 是不变的。您可以随时将Vector3d 的定义从数组切换到struct 并返回,您不必更改函数声明。在任何一种情况下,函数都会“通过引用”接收一个聚合对象(这有例外,但在本讨论的上下文中,这是正确的)。
但是,您不会经常看到这种数组传递方法被显式使用,这仅仅是因为太多人对相当复杂的语法感到困惑,并且对 C 语言的这些特性不够满意,无法正确使用它们。出于这个原因,在现实生活中,将数组作为指向其第一个元素的指针传递是一种更流行的方法。它只是看起来“更简单”。
但实际上,使用指向第一个元素的指针进行数组传递是一种非常小众的技术,一种技巧,它服务于一个非常特定的目的:它的唯一目的是促进传递不同大小的数组 /em>(即运行时大小)。如果您确实需要能够处理运行时大小的数组,那么传递此类数组的正确方法是通过指向其第一个元素的指针,具体大小由附加参数提供
void foo(char p[], unsigned plen);
实际上,在许多情况下,能够处理运行时大小的数组非常有用,这也有助于该方法的普及。许多 C 开发人员根本没有遇到(或从未意识到)需要处理固定大小的数组,因此忽略了正确的固定大小技术。
不过,如果数组大小是固定的,则将其作为指向元素的指针传递
void foo(char p[])
是一个主要的技术级错误,不幸的是,如今这种错误相当普遍。在这种情况下,指向数组的技术是一种更好的方法。
另一个可能阻碍采用固定大小数组传递技术的原因是天真的方法在动态分配的数组类型中占主导地位。例如,如果程序调用char[10] 类型的固定数组(如您的示例中所示),普通开发人员将malloc 此类数组为
char *p = malloc(10 * sizeof *p);
这个数组不能传递给声明为的函数
void foo(char (*p)[10]);
这让普通开发人员感到困惑,并让他们放弃固定大小的参数声明而没有进一步考虑。但实际上,问题的根源在于幼稚的malloc 方法。上面显示的malloc 格式应该保留给运行时大小的数组。如果数组类型具有编译时大小,malloc 的更好方法如下所示
char (*p)[10] = malloc(sizeof *p);
这当然可以很容易地传递给上面声明的foo
foo(p);
并且编译器将执行正确的类型检查。但同样,这对于没有准备的 C 开发人员来说过于混乱,这就是为什么您不会在“典型”的普通日常代码中经常看到它。