你在帖子中所说的是绝对正确的。我认为每个 C 开发者在达到一定的 C 语言熟练水平时都会做出完全相同的发现和结论。
当你的应用领域需要一个特定大小的数组(数组大小是编译时常量)时,传递这样的数组到函数中的唯一正确方式是使用指向数组的指针参数。
void foo(char (*p)[10]);
(在C++语言中,这也可以通过引用来实现)
void foo(char (&p)[10]);
这将启用语言级别的类型检查,确保作为参数提供了完全正确大小的数组。实际上,在许多情况下,人们会隐式地使用这种技术,甚至没有意识到将数组类型隐藏在typedef名称后面。
typedef int Vector3d[3];
void transform(Vector3d *vector);
...
Vector3d vec;
...
transform(&vec);
请注意,上述代码与
Vector3d
类型是数组还是
struct
无关。您可以随时从数组切换到
struct
的定义或者反过来,而不必更改函数声明。无论哪种情况,这些函数将通过引用接收聚合对象(在此讨论的上下文中,有一些例外情况,但这是真实的)。
然而,你不会经常看到这种显式使用数组传递的方法,因为太多人被相当复杂的语法弄糊涂了,并且对C语言的这种特性不够熟悉。因此,在现实生活中,将数组作为指向其第一个元素的指针传递是更受欢迎的方法。它看起来“简单”。
但实际上,使用指向第一个元素的指针进行数组传递是一种非常狭窄的技巧,一种技巧,它只服务于一个非常具体的目的:它唯一的目的是方便传递不同大小(即运行时大小)的数组。如果您确实需要能够处理运行时大小的数组,则通过指向其第一个元素的指针传递这样的数组的正确方式是通过附加参数提供的具体大小。
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开发人员来说过于复杂,这就是为什么您在“典型”的日常代码中很少看到它的原因。
10
可以被作用域内的任何变量替换。 - M.M