为什么使用数组大小​​1而不是指针?

时间:2011-06-17 18:44:49

标签: c++ c

在一个C ++开源项目中,我看到了这一点。

struct SomeClass {
  ...
  size_t data_length;
  char data[1];
  ...
}

这样做有什么好处而不是使用指针?

struct SomeClass {
  ...
  size_t data_length;
  char* data;
  ...
}

我唯一能想到的是使用size 1数组版本,用户不会看到NULL。还有别的吗?

6 个答案:

答案 0 :(得分:35)

有了这个,你不必在其他地方分配内存并使指针指向它。

  • 没有额外的内存管理
  • 对内存的访问将更有可能触及内存缓存

诀窍是分配比sizeof (SomeClass)更多的内存,并指向它SomeClass*。然后,SomeClass对象将使用初始内存,data可以使用剩余的内存。也就是说,你可以说p->data[0]但也可以说p->data[1]等等,直到你达到你分配的内存的末尾。

可以指出,这种使用会导致未定义的行为,因为您声明您的数组只有一个元素,但访问它就好像它包含更多元素一样。但是真正的编译器确实允许这个具有预期意义,因为C ++没有替代语法来形成这些方法(C99有,它在那里被称为“灵活的数组成员”)。

答案 1 :(得分:19)

这通常是避免多个内存分配和解除分配的快速(和脏)方式,尽管它比C ++更时尚。

即代替:

struct SomeClass *foo = malloc(sizeof *foo);
foo->data = malloc(data_len);
memcpy(foo->data,data,data_len);

....
free(foo->data);
free(foo);

你做这样的事情:

struct SomeClass *foo = malloc(sizeof *foo + data_len);
memcpy(foo->data,data,data_len);

...
free(foo);

除了保存(de)分配调用之外,这还可以节省一些内存,因为没有指针空间,你甚至可以使用原本可能是struct padding的空间。

答案 2 :(得分:10)

通常您将此视为结构的最终成员。然后malloc结构的任何人,将在内存中连续分配所有数据字节作为一个块来“跟随”结构。

因此,如果您需要16个字节的数据,则需要分配如下的实例:

SomeClass * pObj = malloc(sizeof(SomeClass) + (16 - 1));

然后您可以像访问数组一样访问数据:

pObj->data[12] = 0xAB;

当然,您也可以通过一次通话释放所有内容。

data成员按惯例是单项数组,因为较旧的C编译器(显然是当前的C ++标准)不允许零大小的数组。这里有很好的进一步讨论:http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html

答案 3 :(得分:10)

在您的示例中,它们在语义上是不同的。

char data[1]是一个有效的char数组,在堆栈上分配了一个未初始化的元素。你可以写data[0] = 'w',你的程序也是正确的。

char* data;只是声明一个无效的指针,直到初始化为指向有效地址为止。

答案 4 :(得分:2)

  1. 可以将结构简单地分配为单个内存块,而不是必须释放的多个分配。

  2. 它实际上使用的内存较少,因为它不需要存储指针本身。

  3. 由于内存是连续的,缓存可能还有性能优势。

答案 5 :(得分:2)

这个特殊事物背后的想法是data的其余部分直接在结构之后适合内存。当然,无论如何你都可以这样做。