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

C结构:初始化的字符串无效,c,struct,C,Struct,下面的代码示例以两种不同的方式获取指向结构的指针。当第一个(“Test1”)成功时,第二个在尝试输出字符串(标题)时失败,并且正确打印了数字(类型): #include <stdio.h> #include <stdlib.h> typedef struct{ unsigned char type; char* title; } MenuItem; typedef struct{ unsigned short itemCount; Me

下面的代码示例以两种不同的方式获取指向结构的指针。当第一个(“Test1”)成功时,第二个在尝试输出字符串(标题)时失败,并且正确打印了数字(类型):

#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]
}
#包括
#包括
类型定义结构{
无符号字符类型;
字符*标题;
}MenuItem;
类型定义结构{
无符号短项计数;
菜单项*项目;
}菜单;
菜单*创建菜单(未签名的短项计数,菜单项[]){
Menu*Menu=malloc(sizeof(Menu));
菜单->项目计数=项目计数;
菜单->项目=项目;
返回菜单;
}
菜单*getSampleMenu(无效){
返回创建菜单(2,(菜单项[]){
{3,“Foo2”},
{4,“Bar2”}
});
}
无效显示菜单(常量菜单*菜单){
对于(无符号短i=0;iitemCount;i++)
printf(“项目%d:%d/%s\n”,i,菜单->项目[i]。类型,菜单->项目[i]。标题);
}
内部主(空){
//测试1
菜单*菜单=创建菜单(2,(菜单项[]){
{1,“Foo”},
{2,“Bar”}
});
显示菜单(菜单);
//结果:1/Foo\n 2/Bar
//测试2
showMenu(getSampleMenu());
//结果:3/[分段错误]
}
你知道可能是什么问题吗?该示例是在Debian上使用GCC4.6.3在C99模式下编译和测试的


提前谢谢

要传递到
createMenu
的数组具有“自动存储持续时间”。一旦
getSampleMenu
结束,它就会消失,指向它的任何指针都将无效

(编辑:它实际上可能比这更严重。数组作为一个临时对象,一旦导致其创建的语句结束,它很可能就死了。在这种情况下,这两个语句大致相当,因为该语句是函数中的最后一个语句……但是
createSampleMenu
中是否有后续语句试图关闭该菜单,即使它们可能遵循无效指针。)


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

传递到
createMenu
的数组具有“自动存储持续时间”。一旦
getSampleMenu
结束,它就会消失,指向它的任何指针都将无效

(编辑:它实际上可能比这更严重。数组作为一个临时对象,一旦导致其创建的语句结束,它很可能就死了。在这种情况下,这两个语句大致相当,因为该语句是函数中的最后一个语句……但是
createSampleMenu
中是否有后续语句试图关闭该菜单,即使它们可能遵循无效指针。)


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

本地声明的变量,也称为“”,通常存储在当前函数的堆栈帧上-因此,当您从声明它们的函数返回时,它们将从堆栈中弹出,稍后调用的函数可以对它们进行写入。
malloc
在堆上分配一个内存范围,在调用
free
,而不考虑代码所在的范围。

本地声明的变量,也称为“”,通常存储在当前函数的堆栈帧上-因此,当您从声明它们的函数返回时,它们将从堆栈中弹出,稍后调用的函数可以对它们进行写入。
malloc
在堆上分配一个内存范围,在调用
free
,而不考虑代码所处的范围。

一旦函数
getSampleMenu()
返回,指针
menu->items
将不再有效,因为“MenuItem[]”是在该函数中本地定义的


因此,在测试2中,当访问
showMenu()
中的
menu->items
时,如果函数
getSampleMenu()
返回,则指针
menu->items
将不再有效,因为“MenuItem[]”是在该函数中本地定义的

因此,在测试2中,当访问
showMenu()
中的
menu->items
时,程序会发生故障