如何在C中包含一个dynamic数组INS?
我环顾四周,但一直未能find解决scheme,必须是一个很好的问题。 这里是我有的代码:
#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
这可能是一个优越的实现(指针算术比数组快,是吗?),但我想在CA声明
char s[]
是相同的
char* s
你现在写的方式,曾经被称为“结构黑客”,直到C99祝福它作为一个“灵活的arrays成员”。 你得到一个错误(可能无论如何)的原因是它需要一个分号后面:
#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一样,如果它是一个一些其他types的数组:
struct dyn_array { int size; int data[]; }; struct dyn_array* my_array = malloc(sizeof(struct dyn_array) + 100 * sizeof(int));
编辑:这将成员更改为一个指针不同的结果。 在这种情况下,您(通常)需要两个单独的分配,一个用于结构本身,另一个用于指针指向的“额外”数据。 使用灵活的数组成员,您可以在一个块中分配所有的数据。
你需要决定你首先要做的是什么。
如果你想有一个指向[独立]数组的指针,你必须声明为
struct my_struct { int n; char *s; };
在这种情况下,您可以以任何方式创build实际的结构对象(例如自动variables)
struct my_struct ms;
然后独立地为arrays分配内存
ms.s = malloc(50 * sizeof *ms.s);
实际上,通常不需要dynamic分配数组内存
struct my_struct ms; char s[50]; ms.s = s;
这一切都取决于你从这些对象需要什么样的生命。 如果你的结构是自动的,那么在大多数情况下,这个数组也是自动的。 如果struct对象拥有数组的内存,那么除此之外根本就没有意义。 如果结构本身是dynamic的,那么数组通常也应该是dynamic的。
请注意,在这种情况下,您有两个独立的内存块:结构和数组。
一个完全不同的方法是使用“struct hack”成语。 在这种情况下,数组成为结构的一个组成部分。 两者都驻留在一块内存中。 在C99中,结构将被声明为
struct my_struct { int n; char s[]; };
并创build一个对象,你必须dynamic地分配整个事情
struct my_struct *ms = malloc(sizeof *ms + 50 * sizeof *ms->s);
在这种情况下,内存块的大小被计算来适应结构成员和运行时间大小的尾部数组。
请注意,在这种情况下,您没有select将静态或自动对象创build为这样的结构对象。 结构灵活的数组成员只能在C中dynamic分配
你关于指针algorithm的假设比数组更快,这是绝对不正确的。 数组通过定义指针算术来工作,所以它们基本相同。 而且,一个真正的数组(不衰减到指针)通常比指针对象快一点。 指针值必须从内存中读取,而数组在内存中的位置是数组对象本身的“已知”(或“计算”)。
数组将parsing为指针,在这里您必须将s
定义为char *s
。 结构基本上是一个容器,并且必须(IIRC)是固定的大小,所以在它内部有一个dynamic大小的数组是不可能的。 因为无论如何你都记忆犹新,这不应该在你以后的事情上有所作为。
基本上你是说, s
会指示一个内存位置。 请注意,您仍然可以使用符号s[0]
稍后访问它。
指针算术比数组快,是吗?
一点也不 – 他们实际上是一样的。 数组在编译时转换为指针算术。
char test[100]; test[40] = 12; // translates to: (test now indicates the starting address of the array) *(test+40) = 12;
只有在结构的末尾才允许使用未指定大小的数组,并且只能在某些编译器中使用。 这是一个非标准的编译器扩展。 (虽然我想我记得C ++ 0x将允许这个。)
该数组不会是一个单独的分配从结构虽然。 所以你需要分配所有的my_struct
,而不仅仅是数组部分。
我所做的只是给数组一个小的,但非零大小。 字符数组通常为4,而wchar_t
数组通常为2,以保持32位alignment。
然后你可以把数组的声明大小考虑进去,当你分配的时候。 我经常没有看到这样一个理论,即在任何情况下,这个斜率都小于堆pipe理者工作的粒度。
另外,我认为你不应该在你的分配中使用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]); }
我怀疑编译器不知道需要为s []分配多less空间,如果你select声明一个自动variables。
我同意本说的,声明你的结构
struct my_struct { int n; char s[1]; };
另外,为了阐明他对存储的评论,声明char *s
不会把结构放在堆栈上(因为它是dynamic分配的)并且在堆中分配s
,它将做的是解释第一个sizeof(char *)
个字节你的数组作为一个指针,所以你不会对你认为的数据进行操作,而且可能是致命的。
记住尽pipe指针和数组的操作可能以同样的方式实现,但它们并不是一回事。
关于C99灵活arrays有很多答案。
我确实想要评论亚历山大·盖斯勒(Alexander Gessler)关于指针与数组相同的答案。
他们不是; 数组是一个expression式,指针是一个variables。
它们会有细微的差别,特别是在遍历大量数据时。 有时你需要挤出每一个毫秒(我工作在embedded式graphics系统)。
生成的代码将是相同的(数组和ptr)。 除了这个数组不会被编译的事实
顺便说一句 – 做它的c + +和使用向量