我环顾四周,但一直无法找到解决问题的问题。 这是我的代码:
#include <stdlib.h>
struct my_struct {
int n;
char s[]
};
int main()
{
struct my_struct ms;
ms.s = malloc(sizeof(char*)*50);
}
这是gcc给我的错误: 错误:无效使用灵活的数组成员
如果我在结构中声明s的声明为
,我可以编译它char* s
这可能是一个优秀的实现(指针算法比数组快,是吗?) 但我在c中声明了
的声明char s[]
与
相同char* s
答案 0 :(得分:66)
你现在写的方式,曾被称为“struct hack”,直到C99祝福它为“灵活的阵列成员”。您收到错误(可能无论如何)的原因是它需要后面跟一个分号:
#include <stdlib.h>
struct my_struct {
int n;
char s[];
};
为此分配空间时,您希望为结构加上分配所需的数据空间大小:
struct my_struct *s = malloc(sizeof(struct my_struct) + 50);
在这种情况下,灵活的数组成员是一个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));
编辑:这会将成员更改为指针,从而产生不同的结果。在这种情况下,您(通常)需要两个单独的分配,一个用于结构本身,另一个用于指针指向的“额外”数据。使用灵活的数组成员,您可以在一个块中分配所有数据。
答案 1 :(得分:19)
你需要先决定你要做的是什么。
如果你想要一个带有指向[独立]数组的指针的结构,你必须将它声明为
struct my_struct {
int n;
char *s;
};
在这种情况下,您可以以任何方式创建实际的struct对象(例如自动变量)
struct my_struct ms;
然后单独为数组分配内存
ms.s = malloc(50 * sizeof *ms.s);
实际上,通常不需要动态分配数组内存
struct my_struct ms;
char s[50];
ms.s = s;
这完全取决于您需要从这些对象中获得什么样的生命周期。如果你的结构是自动的,那么在大多数情况下,数组也是自动的。如果struct对象拥有数组内存,那么其他方面就没有意义了。如果结构本身是动态的,那么数组通常也应该是动态的。
请注意,在这种情况下,您有两个独立的内存块:struct和array。
完全不同的方法是使用“struct hack”成语。在这种情况下,数组成为结构的组成部分。两者都驻留在单个内存块中。在C99中,结构将声明为
struct my_struct {
int n;
char s[];
};
并创建一个对象,你必须动态分配整个事物
struct my_struct *ms = malloc(sizeof *ms + 50 * sizeof *ms->s);
计算此情况下的内存块大小以容纳struct成员和运行时大小的尾随数组。
请注意,在这种情况下,您无法选择创建静态或自动对象等结构对象。末尾具有灵活数组成员的结构只能在C中动态分配。
关于指针aritmetics的假设比数组更快是完全错误的。根据定义,数组通过指针算术运算,因此它们基本相同。而且,真正的数组(不衰减到指针)通常比指针对象快一点。必须从内存中读取指针值,而数组在内存中的位置是从数组对象本身“已知”(或“计算”)。
答案 2 :(得分:1)
只允许在结构的末尾使用未指定大小的数组,并且只能在某些编译器中使用。它是一个非标准的编译器扩展。 (虽然我想我记得C ++ 0x会允许这样做。)
尽管数组不是单独的分配。因此,您需要分配所有my_struct
,而不仅仅是数组部分。
我所做的只是给阵列一个小而非零的大小。对于字符数组通常为4,对于wchar_t
数组通常为2以保持32位对齐。
然后,在进行分配时,可以考虑数组的声明大小。我经常不认为slop小于堆管理器在任何情况下工作的粒度。
另外,我认为您不应该在分配中使用sizeof(char *)。
这就是我要做的。
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]);
}
答案 3 :(得分:0)
数组将解析为指针,此处必须将s
定义为char *s
。结构基本上是一个容器,并且必须(IIRC)是固定大小的,因此在其内部具有动态大小的数组是不可能的。因为你无论如何malloc
记忆,这对你所追求的事情没有任何影响。
基本上你说,s
表示内存位置。请注意,您稍后仍可使用s[0]
等符号来访问此页。
答案 4 :(得分:0)
指针算法比数组快,是吗?
完全没有 - 他们实际上是一样的。数组在编译时转换为指针算术。
char test[100];
test[40] = 12;
// translates to: (test now indicates the starting address of the array)
*(test+40) = 12;
答案 5 :(得分:0)
我怀疑编译器不知道为s []分配多少空间,如果你选择用它声明一个自动变量。
我同意Ben所说的,声明你的结构
struct my_struct {
int n;
char s[1];
};
另外,为了澄清他对存储的评论,声明char *s
不会将结构放在堆栈上(因为它是动态分配的)并在堆中分配s
,它将做的是将数组的第一个sizeof(char *)
字节解释为指针,这样您就不会对您认为的数据进行操作,并且可能会致命。
至关重要的是要记住,尽管指针和数组上的操作可能以相同的方式实现,但它们并不是一回事。
答案 6 :(得分:-6)
生成的代码将是相同的(数组和ptr)。除了数组之外不会编译
的事实和BTW - 做c ++并使用vector