8

引用 C-std 第 6.7.2.1 节,

struct s { int n; double d[]; };

这是一个有效的结构声明。我正在寻找这种语法的一些实际用途。准确地说,这个构造比保持 double* 作为第二个元素更强大或更弱?或者这是另一种“你可以以多种方式做到”的情况?

阿潘

4

4 回答 4

13

C FAQ正好回答了这个问题。快速的回答是,这个结构将包含结构double内部的数组,而不是指向结构外部数组的指针。作为一个简单的示例,您可以使用您的结构,如下例所示:

struct s mystruct = malloc(sizeof(struct s) + 5 * sizeof(double));
s.n = 12;
s.d[0] = 4.0;
s.d[1] = 5.0;
s.d[2] = 6.0;
s.d[3] = 7.0;
s.d[4] = 8.0;

依此类推——你关心的数组的大小包含在分配中,然后你可以像使用任何数组一样使用它。通常这样的类型包含大小作为结构的一部分,因为在这种情况下使用+跳过类型数组的技巧s必然会变得复杂。

对于您添加的问题“与将 [pointer] 保留为第二个元素相比,此构造的功能如何更强或更弱?”,它本身并没有更强大,但您不需要保留指针,因此您可以节省至少有那么多空间——当你复制结构时,你也会复制数组,而不是一个指向数组的指针——有时会有细微的差别,但有时非常重要。“您可以通过多种方式进行操作”可能是一个很好的解释,但在某些情况下,您会特别想要一种或另一种设计。

于 2010-06-15T17:36:12.200 回答
5

主要优点是灵活的数组成员允许您为数组分配单个内存块以及结构中的其他数据(使用指针,您通常会得到两个单独分配的块)。

它对于通过相当多的网络协议传输的数据也很有用,其中传入流的定义方式相同——一个整数定义一个长度,然后是许多数据单位(通常是字节/八位字节)。您可以(通常)使用类型双关将具有灵活数组成员的结构覆盖到填充此类数据的缓冲区上,并直接使用它,而不必将其解析成片段然后单独使用这些片段。

于 2010-06-15T17:52:18.393 回答
3

您可以使用它将标头字段添加到动态分配的数组中,其中最常见的是它的大小:

struct int_array
{
    size_t size;
    int values[];
};

struct int_array *foo = malloc(sizeof *foo + 42 * sizeof *foo->values);
foo->size = 42;

...

for(size_t i = 0; i < foo->size; ++i)
    foo->values[i] = i * i;

您可以通过使用int *成员并单独分配数组来获得类似的结果,但是在内存(附加指针,第二个内存块的堆管理)和运行时(附加间接,第二个分配)方面效率都会降低。

于 2010-06-15T17:41:17.093 回答
0

我已经看到这在 Windows 上用于按长度标记的字符串。字符数据在长度之后直接存储在内存中,将所有内容整齐地放在一起。

typedef struct {
    SIZE_T bytes;
    TCHAR chars[];
} tagged_string;
于 2010-06-15T17:36:18.837 回答