如何将动态数组包含在C中的结构体中?

时间:2022-09-06 11:22:49

I have looked around but have been unable to find a solution to what must be a well asked question. Here is the code I have:

我四处看了看,但没能找到解决这个问题的办法。下面是我的代码:

 #include <stdlib.h>

struct my_struct {
    int n;
    char s[]
};

int main()
{
    struct my_struct ms;
    ms.s = malloc(sizeof(char*)*50);
}

and here is the error gcc gives me: error: invalid use of flexible array member

这里是gcc给我的错误:错误:使用灵活的数组成员无效。

I can get it to compile if i declare the declaration of s inside the struct to be

如果我在struct中声明s,我就可以编译它

char* s

and this is probably a superior implementation (pointer arithmetic is faster than arrays, yes?) but I thought in c a declaration of

这可能是一个更好的实现(指针算术比数组快,是吗?

char s[]

is the same as

是一样的

char* s

8 个解决方案

#1


61  

The way you have it written now , used to be called the "struct hack", until C99 blessed it as a "flexible array member". The reason you're getting an error (probably anyway) is that it needs to be followed by a semicolon:

你现在写它的方式,曾经被称为“struct hack”,直到C99将它祝福为“灵活的数组成员”。你得到错误的原因(也许无论如何)是它需要在后面加一个分号:

#include <stdlib.h>

struct my_struct {
    int n;
    char s[];
};

When you allocate space for this, you want to allocate the size of the struct plus the amount of space you want for the array:

当你为它分配空间时,你想要分配结构体的大小加上你想要为数组分配的空间量:

struct my_struct *s = malloc(sizeof(struct my_struct) + 50);

In this case, the flexible array member is an array of char, and sizeof(char)==1, so you don't need to multiply by its size, but just like any other malloc you'd need to if it was an array of some other type:

在这种情况下,灵活的数组成员是char数组,sizeof(char)= 1,所以不需要乘以它的大小,但是就像任何其他malloc一样,如果它是其他类型的数组,就需要:

struct dyn_array { 
    int size;
    int data[];
};

struct dyn_array* my_array = malloc(sizeof(struct dyn_array) + 100 * sizeof(int));

Edit: This gives a different result from changing the member to a pointer. In that case, you (normally) need two separate allocations, one for the struct itself, and one for the "extra" data to be pointed to by the pointer. Using a flexible array member you can allocate all the data in a single block.

编辑:这与将成员更改为指针有不同的结果。在这种情况下,您(通常)需要两个单独的分配,一个用于结构体本身,另一个用于指针指向的“额外”数据。使用灵活的数组成员,您可以在一个块中分配所有数据。

#2


17  

You need to decide what it is you are trying to do first.

你需要决定你首先要做的是什么。


If you want to have a struct with a pointer to an [independent] array inside, you have to declare it as

如果你想要一个包含指向[独立]数组的指针的结构体,你必须声明它为

struct my_struct { 
  int n; 
  char *s;
}; 

In this case you can create the actual struct object in any way you please (like an automatic variable, for example)

在这种情况下,您可以以任何您喜欢的方式创建实际的struct对象(例如,自动变量)

struct my_struct ms;

and then allocate the memory for the array independently

然后分别为数组分配内存。

ms.s = malloc(50 * sizeof *ms.s);  

In fact, there's no general need to allocate the array memory dynamically

事实上,没有必要动态地分配数组内存。

struct my_struct ms;
char s[50];

ms.s = s;

It all depends on what kind of lifetime you need from these objects. If your struct is automatic, then in most cases the array would also be automatic. If the struct object owns the array memory, there's simply no point in doing otherwise. If the struct itself is dynamic, then the array should also normally be dynamic.

这完全取决于你需要从这些对象中获得什么样的生命周期。如果您的结构是自动的,那么在大多数情况下,数组也是自动的。如果struct对象拥有数组内存,那么做其他操作就毫无意义。如果结构本身是动态的,那么数组也应该是动态的。

Note that in this case you have two independent memory blocks: the struct and the array.

注意,在本例中有两个独立的内存块:struct和数组。


A completely different approach would be to use the "struct hack" idiom. In this case the array becomes an integral part of the struct. Both reside in a single block of memory. In C99 the struct would be declared as

另一种完全不同的方法是使用“struct hack”习语。在这种情况下,数组成为结构体的组成部分。它们都驻留在一个内存块中。在C99中,结构体被声明为

struct my_struct { 
  int n; 
  char s[];
}; 

and to create an object you'd have to allocate the whole thing dynamically

要创建一个对象,你必须动态地分配整个对象

struct my_struct *ms = malloc(sizeof *ms + 50 * sizeof *ms->s);

The size of memory block in this case is calculated to accommodate the struct members and the trailing array of run-time size.

在这种情况下,计算内存块的大小以适应运行时大小的struct成员和尾随数组。

Note that in this case you have no option to create such struct objects as static or automatic objects. Structs with flexible array members at the end can only be allocated dynamically in C.

注意,在这种情况下,您不能选择创建诸如静态或自动对象之类的struct对象。最后带有灵活数组成员的结构只能在C中动态分配。


Your assumption about pointer aritmetics being faster then arrays is absolutely incorrect. Arrays work through pointer arithmetics by definition, so they are basically the same. Moreover, a genuine array (not decayed to a pointer) is generally a bit faster than a pointer object. Pointer value has to be read from memory, while the array's location in memory is "known" (or "calculated") from the array object itself.

关于指针参数比数组快的假设是完全错误的。根据定义,数组可以通过指针算法工作,所以它们基本上是相同的。此外,一个真正的数组(没有衰减到指针)通常比一个指针对象要快一些。指针值必须从内存中读取,而数组在内存中的位置是来自数组对象本身的“已知”(或“计算”)。

#3


1  

The use of an array of unspecified size is only allowed at the end of a structure, and only works in some compilers. It is a non-standard compiler extension. (Although I think I remember C++0x will be allowing this.)

只允许在结构的末尾使用未指定大小的数组,并且只能在某些编译器中使用。它是一个非标准的编译器扩展。(虽然我记得c++ 0x允许这样做。)

The array will not be a separate allocation for from the structure though. So you need to allocate all of my_struct, not just the array part.

不过,该数组与结构不会是单独的分配。所以你需要分配所有的my_struct,而不仅仅是数组部分。

What I do is simply give the array a small but non-zero size. Usually 4 for character arrays and 2 for wchar_t arrays to preserve 32 bit alignment.

我所做的只是给数组一个小但非零的大小。通常字符数组为4,wchar_t数组为2,以保持32位对齐。

Then you can take the declared size of the array into account, when you do the allocating. I often don't on the theory that the slop is smaller than the granularity that the heap manager works in in any case.

然后,在进行分配时,可以考虑数组的声明大小。我通常不认为在任何情况下,slop都小于堆管理器工作的粒度。

Also, I think you should not be using sizeof(char*) in your allocation.

另外,我认为您不应该在分配中使用sizeof(char*)。

This is what I would do.

这就是我要做的。

struct my_struct {
    int nAllocated;
    char s[4]; // waste 32 bits to guarantee alignment and room for a null-terminator
};

int main()
{
    struct my_struct * pms;
    int cb = sizeof(*pms) + sizeof(pms->s[0])*50;
    pms = (struct my_struct*) malloc(cb);
    pms->nAllocated = (cb - sizoef(*pms) + sizeof(pms->s)) / sizeof(pms->s[0]);
}

#4


0  

Arrays will resolve to pointers, and here you must define s as char *s. The struct basically is a container, and must (IIRC) be fixed size, so having a dynamically sized array inside of it simply isn't possible. Since you're mallocing the memory anyway, this shouldn't make any difference in what you're after.

数组将解析为指针,这里必须将s定义为char *s。结构基本上是一个容器,并且必须(IIRC)是固定大小的,所以在它里面有一个动态大小的数组是不可能的。既然你不管怎样都在对记忆进行错误定位,这就不会对你追求的东西产生任何影响。

Basically you're saying, s will indicate a memory location. Note that you can still access this later using notation like s[0].

基本上你说,s表示一个内存位置。注意,您以后仍然可以使用类似于s[0]的符号来访问它。

#5


0  

pointer arithmetic is faster than arrays, yes?

指针运算比数组快,对吗?

Not at all - they're actually the same. arrays translate to pointer arithmetics at compile-time.

一点也不,它们其实是一样的。数组在编译时转换为指针算术。

char test[100];
test[40] = 12;

// translates to: (test now indicates the starting address of the array)
*(test+40) = 12;

#6


0  

I suspect the compiler doesn't know how much space it will need to allocate for s[], should you choose to declare an automatic variable with it.

我怀疑编译器不知道它需要为s[]分配多少空间,如果您选择用它声明一个自动变量的话。

I concur with what Ben said, declare your struct

我同意本说的,把你的结构申报出来

struct my_struct {
    int n;
    char s[1];
};

Also, to clarify his comment about storage, declaring char *s won't put the struct on the stack (since it is dynamically allocated) and allocate s in the heap, what it will do is interpret the first sizeof(char *) bytes of your array as a pointer, so you won't be operating on the data you think you are, and probably will be fatal.

澄清他的评论存储,宣布char *年代不会把结构体在堆栈上(因为它是动态分配)和s在堆中分配内存时,它会解释第一个sizeof(char *)字节的数组指针,所以你不会操作的数据你认为你是谁,和可能会是致命的。

It is vital to remember that although the operations on pointers and arrays may be implemented the same way, they are not the same thing.

重要的是要记住,尽管指针和数组的操作可能以相同的方式实现,但它们不是相同的东西。

#7


0  

There are plenty of answers regarding the C99 flexible array.

关于C99柔性阵列有很多答案。

I did want to comment on Alexander Gessler answer regarding pointers being the same as arrays.

我确实想评论一下Alexander Gessler关于指针与数组相同的答案。

They are not; Arrays is an expression, pointers are a variable.

他们不是;数组是一个表达式,指针是一个变量。

They DO have subtle differences especially when traversing over LARGE amounts of data. Sometimes you do need to squeeze out every mSec (I work on embedded graphics systems).

它们确实存在细微的差异,尤其是在遍历大量数据时。有时你确实需要挤出每一个mSec(我在嵌入式图形系统上工作)。

#8


-6  

the code generated will be identical (array and ptr). Apart from the fact that the array one wont compile that is

生成的代码将是相同的(数组和ptr)。除了数组不能编译这个事实

and BTW - do it c++ and use vector

顺便说一下,用c++和向量。

#1


61  

The way you have it written now , used to be called the "struct hack", until C99 blessed it as a "flexible array member". The reason you're getting an error (probably anyway) is that it needs to be followed by a semicolon:

你现在写它的方式,曾经被称为“struct hack”,直到C99将它祝福为“灵活的数组成员”。你得到错误的原因(也许无论如何)是它需要在后面加一个分号:

#include <stdlib.h>

struct my_struct {
    int n;
    char s[];
};

When you allocate space for this, you want to allocate the size of the struct plus the amount of space you want for the array:

当你为它分配空间时,你想要分配结构体的大小加上你想要为数组分配的空间量:

struct my_struct *s = malloc(sizeof(struct my_struct) + 50);

In this case, the flexible array member is an array of char, and sizeof(char)==1, so you don't need to multiply by its size, but just like any other malloc you'd need to if it was an array of some other type:

在这种情况下,灵活的数组成员是char数组,sizeof(char)= 1,所以不需要乘以它的大小,但是就像任何其他malloc一样,如果它是其他类型的数组,就需要:

struct dyn_array { 
    int size;
    int data[];
};

struct dyn_array* my_array = malloc(sizeof(struct dyn_array) + 100 * sizeof(int));

Edit: This gives a different result from changing the member to a pointer. In that case, you (normally) need two separate allocations, one for the struct itself, and one for the "extra" data to be pointed to by the pointer. Using a flexible array member you can allocate all the data in a single block.

编辑:这与将成员更改为指针有不同的结果。在这种情况下,您(通常)需要两个单独的分配,一个用于结构体本身,另一个用于指针指向的“额外”数据。使用灵活的数组成员,您可以在一个块中分配所有数据。

#2


17  

You need to decide what it is you are trying to do first.

你需要决定你首先要做的是什么。


If you want to have a struct with a pointer to an [independent] array inside, you have to declare it as

如果你想要一个包含指向[独立]数组的指针的结构体,你必须声明它为

struct my_struct { 
  int n; 
  char *s;
}; 

In this case you can create the actual struct object in any way you please (like an automatic variable, for example)

在这种情况下,您可以以任何您喜欢的方式创建实际的struct对象(例如,自动变量)

struct my_struct ms;

and then allocate the memory for the array independently

然后分别为数组分配内存。

ms.s = malloc(50 * sizeof *ms.s);  

In fact, there's no general need to allocate the array memory dynamically

事实上,没有必要动态地分配数组内存。

struct my_struct ms;
char s[50];

ms.s = s;

It all depends on what kind of lifetime you need from these objects. If your struct is automatic, then in most cases the array would also be automatic. If the struct object owns the array memory, there's simply no point in doing otherwise. If the struct itself is dynamic, then the array should also normally be dynamic.

这完全取决于你需要从这些对象中获得什么样的生命周期。如果您的结构是自动的,那么在大多数情况下,数组也是自动的。如果struct对象拥有数组内存,那么做其他操作就毫无意义。如果结构本身是动态的,那么数组也应该是动态的。

Note that in this case you have two independent memory blocks: the struct and the array.

注意,在本例中有两个独立的内存块:struct和数组。


A completely different approach would be to use the "struct hack" idiom. In this case the array becomes an integral part of the struct. Both reside in a single block of memory. In C99 the struct would be declared as

另一种完全不同的方法是使用“struct hack”习语。在这种情况下,数组成为结构体的组成部分。它们都驻留在一个内存块中。在C99中,结构体被声明为

struct my_struct { 
  int n; 
  char s[];
}; 

and to create an object you'd have to allocate the whole thing dynamically

要创建一个对象,你必须动态地分配整个对象

struct my_struct *ms = malloc(sizeof *ms + 50 * sizeof *ms->s);

The size of memory block in this case is calculated to accommodate the struct members and the trailing array of run-time size.

在这种情况下,计算内存块的大小以适应运行时大小的struct成员和尾随数组。

Note that in this case you have no option to create such struct objects as static or automatic objects. Structs with flexible array members at the end can only be allocated dynamically in C.

注意,在这种情况下,您不能选择创建诸如静态或自动对象之类的struct对象。最后带有灵活数组成员的结构只能在C中动态分配。


Your assumption about pointer aritmetics being faster then arrays is absolutely incorrect. Arrays work through pointer arithmetics by definition, so they are basically the same. Moreover, a genuine array (not decayed to a pointer) is generally a bit faster than a pointer object. Pointer value has to be read from memory, while the array's location in memory is "known" (or "calculated") from the array object itself.

关于指针参数比数组快的假设是完全错误的。根据定义,数组可以通过指针算法工作,所以它们基本上是相同的。此外,一个真正的数组(没有衰减到指针)通常比一个指针对象要快一些。指针值必须从内存中读取,而数组在内存中的位置是来自数组对象本身的“已知”(或“计算”)。

#3


1  

The use of an array of unspecified size is only allowed at the end of a structure, and only works in some compilers. It is a non-standard compiler extension. (Although I think I remember C++0x will be allowing this.)

只允许在结构的末尾使用未指定大小的数组,并且只能在某些编译器中使用。它是一个非标准的编译器扩展。(虽然我记得c++ 0x允许这样做。)

The array will not be a separate allocation for from the structure though. So you need to allocate all of my_struct, not just the array part.

不过,该数组与结构不会是单独的分配。所以你需要分配所有的my_struct,而不仅仅是数组部分。

What I do is simply give the array a small but non-zero size. Usually 4 for character arrays and 2 for wchar_t arrays to preserve 32 bit alignment.

我所做的只是给数组一个小但非零的大小。通常字符数组为4,wchar_t数组为2,以保持32位对齐。

Then you can take the declared size of the array into account, when you do the allocating. I often don't on the theory that the slop is smaller than the granularity that the heap manager works in in any case.

然后,在进行分配时,可以考虑数组的声明大小。我通常不认为在任何情况下,slop都小于堆管理器工作的粒度。

Also, I think you should not be using sizeof(char*) in your allocation.

另外,我认为您不应该在分配中使用sizeof(char*)。

This is what I would do.

这就是我要做的。

struct my_struct {
    int nAllocated;
    char s[4]; // waste 32 bits to guarantee alignment and room for a null-terminator
};

int main()
{
    struct my_struct * pms;
    int cb = sizeof(*pms) + sizeof(pms->s[0])*50;
    pms = (struct my_struct*) malloc(cb);
    pms->nAllocated = (cb - sizoef(*pms) + sizeof(pms->s)) / sizeof(pms->s[0]);
}

#4


0  

Arrays will resolve to pointers, and here you must define s as char *s. The struct basically is a container, and must (IIRC) be fixed size, so having a dynamically sized array inside of it simply isn't possible. Since you're mallocing the memory anyway, this shouldn't make any difference in what you're after.

数组将解析为指针,这里必须将s定义为char *s。结构基本上是一个容器,并且必须(IIRC)是固定大小的,所以在它里面有一个动态大小的数组是不可能的。既然你不管怎样都在对记忆进行错误定位,这就不会对你追求的东西产生任何影响。

Basically you're saying, s will indicate a memory location. Note that you can still access this later using notation like s[0].

基本上你说,s表示一个内存位置。注意,您以后仍然可以使用类似于s[0]的符号来访问它。

#5


0  

pointer arithmetic is faster than arrays, yes?

指针运算比数组快,对吗?

Not at all - they're actually the same. arrays translate to pointer arithmetics at compile-time.

一点也不,它们其实是一样的。数组在编译时转换为指针算术。

char test[100];
test[40] = 12;

// translates to: (test now indicates the starting address of the array)
*(test+40) = 12;

#6


0  

I suspect the compiler doesn't know how much space it will need to allocate for s[], should you choose to declare an automatic variable with it.

我怀疑编译器不知道它需要为s[]分配多少空间,如果您选择用它声明一个自动变量的话。

I concur with what Ben said, declare your struct

我同意本说的,把你的结构申报出来

struct my_struct {
    int n;
    char s[1];
};

Also, to clarify his comment about storage, declaring char *s won't put the struct on the stack (since it is dynamically allocated) and allocate s in the heap, what it will do is interpret the first sizeof(char *) bytes of your array as a pointer, so you won't be operating on the data you think you are, and probably will be fatal.

澄清他的评论存储,宣布char *年代不会把结构体在堆栈上(因为它是动态分配)和s在堆中分配内存时,它会解释第一个sizeof(char *)字节的数组指针,所以你不会操作的数据你认为你是谁,和可能会是致命的。

It is vital to remember that although the operations on pointers and arrays may be implemented the same way, they are not the same thing.

重要的是要记住,尽管指针和数组的操作可能以相同的方式实现,但它们不是相同的东西。

#7


0  

There are plenty of answers regarding the C99 flexible array.

关于C99柔性阵列有很多答案。

I did want to comment on Alexander Gessler answer regarding pointers being the same as arrays.

我确实想评论一下Alexander Gessler关于指针与数组相同的答案。

They are not; Arrays is an expression, pointers are a variable.

他们不是;数组是一个表达式,指针是一个变量。

They DO have subtle differences especially when traversing over LARGE amounts of data. Sometimes you do need to squeeze out every mSec (I work on embedded graphics systems).

它们确实存在细微的差异,尤其是在遍历大量数据时。有时你确实需要挤出每一个mSec(我在嵌入式图形系统上工作)。

#8


-6  

the code generated will be identical (array and ptr). Apart from the fact that the array one wont compile that is

生成的代码将是相同的(数组和ptr)。除了数组不能编译这个事实

and BTW - do it c++ and use vector

顺便说一下,用c++和向量。