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

Rus*_*ell 46 c c++

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

struct SomeClass {
  ...
  size_t data_length;
  char data[1];
  ...
}
Run Code Online (Sandbox Code Playgroud)

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

struct SomeClass {
  ...
  size_t data_length;
  char* data;
  ...
}
Run Code Online (Sandbox Code Playgroud)

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

Joh*_*itb 36

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

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

诀窍是分配更多的内存sizeof (SomeClass),并SomeClass*指出它.然后,您的SomeClass对象将使用初始内存,并且可以使用剩余的内存data.也就是说,你可以说p->data[0]也是p->data[1]等,直到你打你分配内存的结束.

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

  • 如果要相信OP的代码示例,那么我认为这个答案是正确的.他在`char data [1]`之后有"......",暗示有更多的字段在跟随. (9认同)
  • @Steve,因为指针指向类型为char [1]的数组的元素。因此,从技术上讲,您只能说“ data [0]”和“ data [1]”。但是data [2]是未定义的行为(不一定是因为取消引用,而是因为data + 2是未定义的行为)。但是实际上,我认为这并不重要,因此,既然允许它实际上是有用的,那么实际的编译器确实会允许它。 (2认同)

Lyk*_*yke 19

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

也就是说,而不是这个:

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

....
free(foo->data);
free(foo);
Run Code Online (Sandbox Code Playgroud)

你做这样的事情:

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

...
free(foo);
Run Code Online (Sandbox Code Playgroud)

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


Ed *_* S. 11

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

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

char* data; 简单地声明一个无效的指针,直到初始化为指向有效地址.

  • 我不确定这是怎么被忽视的.指针和字符不是一回事. (3认同)

Ben*_*tto 10

通常您将此视为结构的最终成员.然后,无论malloc结构是谁,都将在内存中连续分配所有数据字节作为一个块来"跟随"结构.

因此,如果您需要16个字节的数据,您将分配一个这样的实例:

SomeClass * pObj = malloc(sizeof(SomeClass) + (16 - 1));
Run Code Online (Sandbox Code Playgroud)

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

pObj->data[12] = 0xAB;
Run Code Online (Sandbox Code Playgroud)

当然,你也可以通过一次通话释放所有的东西.

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