2012-10-18 133 views
-2

比方说,我有一个结构:内存分配

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; 
} 
  1. 任何人都可以澄清我如何记忆被分配(堆vs堆栈)在标记的情况下?
  2. 我应该如何在主块的末尾释放内存?
  3. 编译器给 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; 
} 
+2

请一次提出一个问题。那里有三种不同的东西,其中前两种已经被问及过无数次了。 – Mat

+0

3.的原因是你不能分配给数组。这是一个灵活的阵列成员是偶然的。 –

+0

@Mat我很想看到这些问题的链接,以便我可以解释为什么这些答案不适用于我.. – none

回答

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来复制)。

的第四壳体

kp->name1 = "this is also my first name"; /* 4th case */ 

类似于情况1 - name1是被设置为指向一个静态文本的指针。

+0

那个'静态数据'的内存管理呢,它在堆还是栈上?我应该在事后释放它吗? – none

+0

不,静态数据是一个单独的区域(不是堆栈而不是堆)。你不必做任何事情,它由系统处理。 –

0

时,你应该释放自己的内存只有时刻当你来(m)分配一些东西,或者调用这样做的函数时(strdup(),...)

在情况1,3和4你分配的条纹在堆栈中,当你离开函数时,这些字符串将不可用。第二种情况有点棘手,但是这个字符串在可执行文件中是硬编码的,并且不能对其进行修改(如果您尝试这样做,则会出现分段错误)。

由于name2不是指针,而是数组,因此不能将name2指向字符串。

+0

请参阅我的编辑问题。 – none

+0

由于您使用的是硬编码字符串,因此该字符串将映射到内存中。但是,无论如何,发生的事情都是未定义的行为。它可以随时分段。 – tomahh

1

灵活长度的数组旨在主要用于指针。

Klass *kp = malloc(sizeof(Klass) + 100); 

这100是额外的字节,可以通过name2成员访问。通常存在用于存储柔性部件尺寸的结构的成员。

释放此内存与您将用于常规结构的内存没有任何区别。

编译器抱怨的原因是它仍然是一个数组(不是指针),你不能简单地分配数组。当您访问kp->name2时,不会引入额外的间接寻址(与name2是指针的情况不同)。

至于存储器分配:

1)name1是指向某些存储器区域(最有可能只读存储器),其中一个字符串文字被存储(字节包含与终止0 char数组)。试图修改name1指向的字符串将导致未定义的行为(您不允许修改字符串文字)。

2)name2是一个数组,它在堆栈中。您可以自由修改其内容。将字符串文字放入此数组的初始化代码在不同的平台和编译器中可能会有所不同。我甚至看到了反汇编,其中一个字符串文字处于只读内存区(.rodata)中,它简单地用memcpy'编辑为'name2。

3)和4)是分配给非法数组的尝试。

+0

我认为你的答案中混合了案例索引,但我想这是因为我的问题与所有这些问题/案例/变量索引混淆。无论如何,我想我已经得到了你的答案,谢谢.. – none

1
    1. 的字符串的内存是静态区域,这是所有的字符串常量住的地方。 name1只是一个指向该地区的指针。
    2. 内存具有自动存储(“在堆栈上”)。
    3. 相同的情况下1
  1. 是的,因为你已经叫malloc。必须通过致电free来镜像每个malloc

  2. Klass,会员name2flexible array member,其大小是未知的编译器(以及其中,顺便说一句,你还没有被分配在malloc调用任何内存)。另外,你不能直接拷贝C中的数组;如果您分配了足够的内存,则可以使用memcpystrcpy

+0

你的答案缺少1.4,但我猜它也与案例1相同 – none

+0

@gokcehan:没有看到它,但它确实是一样的。 –