简体   繁体   English

为什么我们使用零长度数组而不是指针?

[英]Why do we use zero length array instead of pointers?

It's said that zero length array is for variable length structure, which I can understand. 据说零长度数组用于可变长度结构,我可以理解。 But what puzzle me is why we don't simply use a pointer, we can dereference and allocate a different size structure in the same way. 但是令我困惑的是为什么我们不只是使用指针,而是可以以相同的方式取消引用并分配不同的大小结构。

EDIT - Added example from comments 编辑-从评论中添加示例

Assuming: 假设:

struct p
{
    char ch;
    int *arr;
};

We can use this: 我们可以这样使用:

struct p *p = malloc(sizeof(*p) + (sizeof(int) * n));

p->arr = (struct p*)(p + 1);

To get a contiguous chunk of memory. 获取连续的内存块。 However, I seemed to forget the space p->arr occupies and it seems to be a disparate thing from the zero size array method. 但是,我似乎忘记了p->arr占据的空间,这与零大小数组方法似乎是完全不同的。

If you use a pointer, the structure would no longer be of variable length: it will have fixed length, but its data will be stored in a different place. 如果使用指针,则该结构将不再具有可变长度:它将具有固定的长度,但是其数据将存储在不同的位置。

The idea behind zero-length arrays * is to store the data of the array "in line" with the rest of the data in the structure, so that the array's data follows the structure's data in memory. 零长度数组*的想法是将数组的数据与其余数据“按行”存储在结构中,以便数组的数据在内存中跟随结构的数据。 Pointer to a separately allocated region of memory does not let you do that. 指向单独分配的内存区域的指针不允许您这样做。


* Such arrays are also known as flexible arrays ; *这样的数组也称为弹性数组 in C99 you declare them as element_type flexArray[] instead of element_type flexArray[0] , ie you drop zero. 在C99中,您将它们声明为element_type flexArray[]而不是element_type flexArray[0] ,即,您将其丢弃为零。

The pointer isn't really needed, so it costs space for no benefit. 实际上并不需要该指针,因此它浪费了空间,没有任何好处。 Also, it might imply another level of indirection, which also isn't really needed. 同样,这可能意味着间接的另一层次,这实际上并不是必需的。

Compare these example declarations, for a dynamic integer array: 比较以下示例声明,以获取动态整数数组:

typedef struct {
  size_t length;
  int    data[0];
} IntArray1;

and: 和:

typedef struct {
  size_t length;
  int    *data;
} IntArray2;

Basically, the pointer expresses "the first element of the array is at this address, which can be anything" which is more generic than is typically needed. 基本上,指针表示的是“数组的第一个元素在此地址,可以是任何东西”,它比通常所需的更为通用。 The desired model is "the first element of the array is right here, but I don't know how large the array is". 所需的模型是“数组的第一个元素就在这里,但我不知道数组有多大”。

Of course, the second form makes it possible to grow the array without risking that the "base" address (the address of the IntArray2 structure itself) changes, which can be really neat. 当然,第二种形式可以在不冒“基本”地址( IntArray2结构本身的地址)变化的风险的情况下扩展数组,这实际上是很整洁的。 You can't do that with IntArray1 , since you need to allocate the base structure and the integer data elements together. 您无法使用IntArray1做到这IntArray1 ,因为您需要将基本结构和整数数据元素一起分配。 Trade-offs, trade-offs ... 权衡,权衡...

These are various forms of the so-called "struct hack", discussed in question 2.6 of the comp.lang.c FAQ . 这些是所谓的“结构hack”的各种形式,在comp.lang.c FAQ的问题2.6中进行了讨论。

Defining an array of size 0 is actually illegal in C, and has been at least since the 1989 ANSI standard. 定义大小为0的数组实际上在C语言中是非法的,至少自1989年ANSI标准以来一直如此。 Some compilers permit it as an extension, but relying on that leads to non-portable code. 一些编译器允许它作为扩展,但是依靠它会导致不可移植的代码。

A more portable way to implement this is to use an array of length 1, for example: 一种更可移植的实现方法是使用长度为1的数组,例如:

struct foo {
    size_t len;
    char str[1];
};

You could allocate more than sizeof (struct foo) bytes, using len to keep track of the allocated size, and then access str[N] to get the Nth element of the array. 您可以分配多个sizeof (struct foo)个字节,使用len跟踪分配的大小,然后访问str[N]获取数组的第N个元素。 Since C compilers typically don't do array bounds checking, this would generally "work". 由于C编译器通常不执行数组边界检查,因此通常可以“工作”。 But, strictly speaking, the behavior is undefined. 但是,严格来说,行为是不确定的。

The 1999 ISO standard added a feature called "flexible array members", intended to replace this usage: 1999年的ISO标准添加了一个称为“灵活数组成员”的功能,旨在替代此用法:

struct foo {
    size_t len;
    char str[];
};

You can deal with these in the same way as the older struct hack, but the behavior is well defined. 您可以使用与较早的struct hack相同的方式来处理这些问题,但是行为已得到明确定义。 But you have to do all the bookkeeping yourself; 但是,您必须自己做所有簿记工作。 sizeof (struct foo) still doesn't include the size of the array, for example. sizeof (struct foo)仍然不包括数组的大小。

You can, of course, use a pointer instead: 当然,您可以使用指针代替:

struct bar {
    size_t len;
    char *ptr;
};

And this is a perfectly good approach, but it has different semantics. 这是一个非常好的方法,但是它具有不同的语义。 The main advantage of the "struct hack", or of flexible array members, is that the array is allocated contiguously with the rest of the structure, and you can copy the array along with the structure using memcpy (as long as the target has been properly allocated). “结构hack”或灵活的数组成员的主要优点是,数组与结构的其余部分连续分配,并且您可以使用memcpy将数组与结构一起复制(只要目标已正确分配)。 With a pointer, the array is allocated separately -- which may or may not be exactly what you want. 使用指针,可以单独分配数组-可能恰恰不是您想要的。

This is because with a pointer you need a separate allocation and assignment. 这是因为使用指针需要单独的分配和分配。

struct WithPointer
{
    int   someOtherField;
    ...
    int*  array;
};

struct WithArray
{
    int someOtherField;
    ...
    int array[1];
};

To get an 'object' of WithPointer you need to do: 要获取WithPointer的“对象”,您需要执行以下操作:

struct WithPointer* withPointer = malloc(sizeof(struct WithPointer));
withPointer.array = malloc(ARRAY_SIZE * sizeof(int));

To get an 'object' of WithArray: 要获取WithArray的“对象”:

struct WithArray* withArray = malloc(sizeof(struct WithArray) + 
                                            (ARRAY_SIZE - 1) * sizeof(int));

That's it. 而已。

In some cases it's also very handy, or even necessary, to have the array in consecutive memory; 在某些情况下,将数组放置在连续的内存中也非常方便,甚至有必要。 for example in network protocol packets. 例如在网络协议数据包中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么我们使用带指针数组的静态? - Why do we use static with array of pointers? 为什么我们在指针算术和数组地址中使用(字节)而不是(位)? - Why do we use (bytes) instead of (bits) in pointers arithmetic and array's addresses? 为什么在引用结构中的数组元素时我们使用指针而不是索引 - why do we use pointers instead of index when referring to array elements in structs 为什么我们对对象使用指针而不是直接使用对象值? - Why do we use pointers for objects instead of just the object value directly? 为什么我们需要使用(void *)&a而不是&a - why do we need to use (void*)&a instead of &a 当用C中的指针定义时,为什么我们使用`const`作为字符串? - Why do we use `const` for strings when defining with pointers in C? 在C语言中,如何使用指针代替数组来更改大小写并打印长度? - In C, how can we use pointers in place of array to change case and print the length? 为什么不能使用指针指向char指针而不是char指针数组? - Why can't one use pointer to char pointers instead of array of char pointers? 为什么以及何时应该在C中使用指针到指针而不是简单的指针? - Why and when should we use pointer-to-pointer instead of simple pointers in C? 为什么将6显示为数组的长度而不是5? - why is it showing the 6 as the length of the array instead of 5?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM