简体   繁体   English

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

[英]How to include a dynamic array INSIDE a struct in C?

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 如果我将s的声明声明为struct,则可以编译它

char* s

and this is probably a superior implementation (pointer arithmetic is faster than arrays, yes?) but I thought in ca declaration of 这可能是一个更好的实现(指针算术比数组快,是吗?),但我认为应该在ca声明中

char s[]

is the same as 是相同的

char* s

The way you have it written now , used to be called the "struct hack", until C99 blessed it as a "flexible array member". 您现在编写的方式曾经被称为“结构黑客”,直到C99将此作为“灵活数组成员”为止。 The reason you're getting an error (probably anyway) is that it needs to be followed by a semicolon: 出现错误的原因(可能仍然如此)是,必须在其后加上分号:

#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. 使用灵活的数组成员,您可以在一个块中分配所有数据。

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 如果您想要一个带有指向[independent]数组的指针的结构,则必须将其声明为

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. 如果struct对象拥有数组内存,那么别无选择。 If the struct itself is dynamic, then the array should also normally be dynamic. 如果结构本身是动态的,则数组通常也应该是动态的。

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 在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. 在这种情况下,将计算内存块的大小以容纳结构成员和运行时大小的尾随数组。

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. 末尾具有灵活数组成员的结构只能在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. 指针值必须从内存中读取,而数组在内存中的位置是从数组对象本身“已知”(或“计算”)的。

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. 在任何情况下,我通常都不会认为Slope小于堆管理器工作的粒度。

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]);
}

Arrays will resolve to pointers, and here you must define s as char *s . 数组将解析为指针,在这里您必须s定义为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. 该结构基本上是一个容器,并且必须(IIRC)大小固定,因此根本不可能在其中包含动态大小的数组。 Since you're malloc ing the memory anyway, this shouldn't make any difference in what you're after. 由于您无论如何都在malloc内存,因此这与您要执行的操作没有任何区别。

Basically you're saying, s will indicate a memory location. 基本上,您是说s表示内存位置。 Note that you can still access this later using notation like s[0] . 请注意,您以后仍然可以使用符号s[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;

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 我同意Ben所说的,声明您的结构

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不会将结构放到堆栈上(因为它是动态分配的),并且不会在堆中分配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. 重要的是要记住,尽管对指针和数组的操作可能以相同的方式实现,但它们并不是同一件事。

the code generated will be identical (array and ptr). 生成的代码将相同(数组和ptr)。 Apart from the fact that the array one wont compile that is 除了数组不会编译的事实之外,

and BTW - do it c++ and use vector 和BTW-使用C ++并使用vector

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM