假设我有一个结构:
typedef struct {
int number1; /* dummy */
int number2; /* dummy */
int number3; /* dummy */
char *name1;
char name2[];
} Klass;
其余代码是:
int main(int argc, char const *argv[])
{
char *name1 = "this is a name"; /* 1st case */
char name2[] = "this is also a name"; /* 2nd case */
Klass k;
k.number1 = 10;
k.number2 = 20;
k.number3 = 30;
k.name1 = "this is my first name"; /* 3rd case */
/* error: invalid use of flexible array member */
k.name2 = "this is my second name";
Klass *kp = (Klass*)malloc(sizeof(Klass));
kp->number1 = 100;
kp->number2 = 200;
kp->number3 = 300;
kp->name1 = "this is also my first name"; /* 4th case */
/* error: invalid use of flexible array member */
kp->name2 = "this is my second name";
return 0;
}
error: invalid use of flexible array member
的原因是什么? 修改
如果你说k.name = "this is my name";
和kp->name = "this is also my name";
在堆栈中,你能解释一下我如何能够"this is my name"
这样:
Klass *kp;
int foo() {
Klass k;
k.number1 = 10;
k.number2 = 20;
k.number3 = 30;
k.name = "this is my name";
kp = &k;
} // k is destroyed now
int main(int argc, char const *argv[])
{
kp = (Klass*)malloc(sizeof(Klass));
foo();
printf("%d\n", kp->number1); /* segfault */
printf("%d\n", kp->number2); /* segfault */
printf("%d\n", kp->number3); /* segfault */
printf("%s\n", kp->name); /* prints "this is my name" */
return 0;
}
答案 0 :(得分:1)
灵活长度的数组主要用于指针。
Klass *kp = malloc( sizeof(Klass) + 100 );
这100个是可以通过name2
成员访问的额外字节。通常,存在用于存储柔性部件尺寸的结构的构件。
释放此内存与您用于常规结构的内存没有任何不同。
编译器抱怨的原因是它仍然是一个数组(不是指针),你不能简单地分配数组。当您访问kp->name2
时,不会引入额外的间接寻址(与name2
是指针的情况不同)。
关于内存分配:
1)name1
是指向存储字符串文字的某些内存区域(很可能是只读内存)的指针(包含终止0的char数组的字节)。尝试修改name1
指向的字符串将导致未定义的行为(不允许修改字符串文字)。
2)name2
是一个数组,它在堆栈中。您可以自由修改其内容。将字符串文字放入此数组的初始化代码在不同平台和编译器之间可能不同。我甚至看到了一个反汇编,其中一个字符串文字在只读内存区域(.rodata)中,它只是memcpy
编辑为`name2。
3)和4)是分配给非法的数组的尝试。
答案 1 :(得分:1)
name1
只是指向该区域的指针。是的,因为你打电话给malloc
。必须通过调用malloc
镜像每个free
。
在Klass
中,成员name2
是flexible array member,其大小对于编译器来说是未知的(为此,你没有分配任何内存在malloc
电话中。另外,你不能直接在C中复制数组;如果您分配了足够的内存,可以使用memcpy
或strcpy
。
答案 2 :(得分:1)
char *name1 = "this is a name"; /* 1st case */
这只是分配一个指针,将其设置为指向字符串(保存为静态数据)。
char name2[] = "this is also a name"; /* 2nd case */
这是char name2[sizeof(init_string)] = "this is also a name";
的缩写,并分配足够的空间来存储字符串中的字符。
你的第三个案例
char name2[];
根本不分配空间!没有地方存储字符串(无论如何都必须使用strcpy
复制)。
第4个案例
kp->name1 = "this is also my first name"; /* 4th case */
与案例1类似 - name1
是一个指向静态文本的指针。
答案 3 :(得分:0)
你应该自己释放记忆的唯一时刻是你来(m)分配一些东西,或者调用一个这样做的函数(strdup()
,...)
在1,3和4的情况下,您在堆栈上分配字符串,当您退出函数时,这些字符串将不可用。第二种情况有点棘手,但是这个字符串在可执行文件中是硬编码的,你不能修改它(如果你试图这样做就会出现分段错误。)
你不能让name2与字符串相关,因为name2不是指针,而是数组。