-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. 谁能为我澄清在标记的情况下如何分配内存(堆与堆栈)?
  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;
}
4

4 回答 4

1

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

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

这 100 个字节是可以通过name2成员访问的额外字节。通常结构中有一个成员用于存储灵活的零件尺寸。

释放此内存与用于常规结构的内存没有任何不同。

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

至于内存分配:

1)name1是指向存储字符串文字的某个内存区域(很可能是只读内存)的指针(包含以 0 结尾的 char 数组的字节)。尝试修改name1指向 的字符串会导致未定义的行为(不允许修改字符串文字)。

2)name2是一个数组,它在堆栈上。您可以自由修改其内容。将字符串文字放入此数组的初始化代码在不同的平台和编译器之间可能会有所不同。我什至看到过反汇编,其中字符串文字位于只读内存区域(.rodata)中,它只是memcpy'ed到'name2。

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

于 2012-10-18T12:57:21.947 回答
1
    1. 字符串的内存位于一个静态区域,这是所有字符串常量所在的位置。name1只是指向该区域的指针。
    2. 内存具有自动存储(“在堆栈上”)。
    3. 与案例 1 相同。
  1. 是的,因为你已经打电话给malloc. 每个都malloc必须通过调用来反映free

  2. Klass中,该成员name2是一个灵活的数组成员,编译器不知道其大小(顺便说一句,您没有在malloc调用中分配任何内存)。此外,您不能直接在 C 中复制数组;如果你分配了足够的内存,你可以使用memcpyor strcpy

于 2012-10-18T12:59:15.940 回答
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是设置为指向静态文本的指针。

于 2012-10-18T12:59:32.583 回答
0

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

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

你不能让 name2 指向一个字符串,因为 name2 不是一个指针,而是一个数组。

于 2012-10-18T12:57:11.333 回答