阅读这个跳过列表实现我遇到了这个代码片段:
typedef struct nodeStructure{
keyType key;
valueType value;
node forward[1]; /* variable sized array of forward pointers */
};
对我来说,这似乎forward[1]
表示一个元素数组。评论称它为可变大小的数组。
我是否误解了某些东西,或者这只是我正在阅读的来源中的一个错误?
它被称为struct hack。它是C99 中引入的灵活数组成员的旧形式。
这在过去被用来模拟结构的最后一个成员中的变量数组,但它不是 C 中严格符合的构造。
这是您有时会看到的 C 中的程序范例。分配结构体时,会分配sizeof(struct nodeStructure + numNodes * sizeof(node))。
这允许您为该结构拥有多个前向节点,即使它仅被声明为有一个。这有点丑陋,但它确实有效。
通常,当您这样做时,还会有一个名为“count”之类的文件,以便您知道节点之后有多少额外的条目。
这是较旧的 C 编译器(C99 之前)的常见技巧:当 ;forward
的最后一个元素时,编译器允许您取消引用超过声明长度末尾的元素struct
。然后,您可以为其他元素malloc
提供足够的内存,如下所示:node
nodeStructure *ptr = malloc(sizeof(nodeStructure)+4*sizeof(node));
for (int i = 0 ; i != 5 ; i++) { // The fifth element is part of the struct
ptr->forward[i] = ...
}
free(ptr);
该技巧使您可以在结构中嵌入可变大小的数组,而无需单独的动态分配。另一种解决方案是声明node *forward
,但随后您需要将其malloc
与free
分开nodeStructure
,不必要地将 s 的数量加倍malloc
并可能增加内存碎片:
以下是没有 hack 的上述片段的外观:
typedef struct nodeStructure{
keyType key;
valueType value;
node *forward;
};
nodeStructure *ptr = malloc(sizeof(nodeStructure));
ptr->forward = malloc(5*sizeof(node));
for (int i = 0 ; i != 5 ; i++) {
ptr->forward[i] = ...
}
free(ptr->forward);
free(ptr);
编辑(回应 Adam Rosenfield 的评论):C99 允许您定义没有大小的数组,如下所示:node forward[];
这称为灵活数组成员,它在 C99 标准的第 6.7.2.1.16 节中定义。
数据结构实现很可能是针对 C90 标准编写的,该标准没有灵活的数组成员(在 C99 中添加)。那时,在结构的末尾使用 1 甚至 0 大小(*)的数组是很常见的,以允许访问那里动态可变数量的元素。
该注释不应被解释为 C99 风格的可变长度数组;此外,在 C99 中,成员的惯用且符合标准的定义forward
将是node forward[];
. 具有此类struct nodeStructure
成员的类型称为不完整类型。您可以定义一个指向它的指针,但您不能定义这种类型的变量或获取它的大小、所有允许node forward[0]
或node forward[1]
允许的操作,尽管这些操作可能与程序员的意图不匹配。
(*) 标准禁止使用 0 大小的数组,但 GCC 接受了这些数组作为这种用途的扩展。