您在帖子中所说的是绝对正确的。我想说的是,每位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
type是数组还是a 是不变的struct
。您可以Vector3d
随时将数组的定义从a 切换到a 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
可以通过任何可变范围被替换