C 指针 : pointing to an array of fixed size

标签 c pointers size

这个问题向那里的 C 大师提出:

在 C 中,可以如下声明指针:

char (* p)[10];

.. 它基本上表明这个指针指向一个 10 个字符的数组。像这样声明指针的巧妙之处在于,如果您尝试将不同大小的数组的指针分配给 p,则会出现编译时错误。如果您尝试将简单 char 指针的值分配给 p,它也会给您一个编译时错误。我用 gcc 试过这个,它似乎适用于 ANSI、C89 和 C99。

在我看来,像这样声明一个指针会非常有用——尤其是在将指针传递给函数时。通常,人们会像这样编写这样一个函数的原型(prototype):
void foo(char * p, int plen);

如果您期望一个特定大小的缓冲区,您只需测试 plen 的值。但是,您不能保证将 p 传递给您的人真的会在该缓冲区中为您提供大量有效的内存位置。你必须相信调用这个函数的人正在做正确的事情。另一方面:
void foo(char (*p)[10]);

..会强制调用者给你一个指定大小的缓冲区。

这似乎非常有用,但我从未在我遇到的任何代码中看到过这样声明的指针。

我的问题是:人们有什么理由不声明这样的指针?我没有看到一些明显的陷阱吗?

最佳答案

您在帖子中所说的绝对正确。我想说每个 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并返回,您不必更改函数声明。在任何一种情况下,函数都将“通过引用”接收一个聚合对象(这有异常(exception),但在本讨论的上下文中,这是真的)。

但是,您不会经常看到这种数组传递方法被显式使用,仅仅是因为太多人对相当复杂的语法感到困惑,并且对 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 开发人员来说过于困惑,这就是为什么你不会在“典型”的普通日常代码中经常看到它。

关于C 指针 : pointing to an array of fixed size,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1810083/

相关文章:

c++ - 无法为 i386 构建 PortAudio 以使其与 NI 的 DAQmxBase 兼容

c - 指向变量与数组的外部指针

java - JScrollPane 内的 JTable : best height to disable scrollbars

c# - 编码一个未知的数组大小

c - 带/不带控制台的 Windows 启动过程

C - 结构内静态字符数组上的 sizeof() - 不可能?

c - 生成结构定义的版本 ID?

c++ - 如果使用 g++,为什么 std::cout 可以转换为 void*?

c++ - cout 对 char * 的特殊处理有何帮助?

c# - 有没有办法设置 UIElement 的宽度和高度?