C结构:初始化字符串变为无效

时间:2013-04-19 15:18:06

标签: c struct

我有以下代码示例,它以两种不同的方式获取指向结构的指针。当第一个(“Test1”)成功时,第二个在尝试输出字符串( title )时失败并出现Segmentation故障,而数字( type )是正确打印:

#include <stdio.h>
#include <stdlib.h>

typedef struct{
    unsigned char type;
    char* title;
} MenuItem;

typedef struct{
    unsigned short itemCount;
    MenuItem *items;    
} Menu;

Menu* createMenu(unsigned short itemCount, MenuItem items[]){
    Menu *menu = malloc(sizeof(Menu));
    menu->itemCount = itemCount;
    menu->items = items;
    return menu;
}

Menu* getSampleMenu(void){
    return createMenu(2,(MenuItem[]){
        {3,"Foo2"},
        {4,"Bar2"}
    });
}

void showMenu(const Menu *menu){
    for(unsigned short i = 0; i < menu->itemCount; i++)
        printf("Item %d: %d/%s\n",i,menu->items[i].type,menu->items[i].title);
}

int main(void){
    //Test 1
    Menu *menu = createMenu(2,(MenuItem[]){
        {1,"Foo"},
        {2,"Bar"}
    });
    showMenu(menu);
    //Result: 1/Foo\n 2/Bar

    //Test 2
    showMenu(getSampleMenu());
    //Result: 3/ [segmentation fault]
}

你知道问题可能是什么吗?该示例使用gcc 4.6.3在C99模式下在Debian上编译和测试。

提前致谢!

3 个答案:

答案 0 :(得分:7)

您传递给createMenu的数组具有“自动存储持续时间”。它会死掉,一旦getSampleMenu结束,它的任何指针都会变为无效。

(编辑:它可能实际上甚至比那更严重。作为临时对象的数组,一旦导致其创建的语句结束,就很可能已经死了。在这种情况下,这两个是关于等价,因为该语句是函数中的最后一个...但是createSampleMenu中的后续语句试图使用该菜单,即使它们可能跟随无效指针。)

您需要动态分配(malloc)一些内存并将数组复制到其中。 (当然,那么你也应该有一个destroyMenu或类似的功能,以便在不再需要菜单后正确释放内存。)

答案 1 :(得分:2)

在本地声明的变量,也称为&#34; automatic&#34;,通常存储在当前函数的堆栈帧中 - 这样当您从声明它们的函数返回时,它们从堆栈中弹出,稍后调用的函数可以写入它们。 malloc在堆上分配一系列内存,在您调用free之前,它仍将分配给您使用,无论您的代码所在的范围如何。

答案 2 :(得分:0)

一旦函数menu->items返回,指针getSampleMenu()就会变长,因为&#34; MenuItem []&#34;在此函数中本地定义。

因此,在测试2中,当您访问menu->items中的showMenu()时,您的程序会出现段错误。