1

我有以下代码示例,它以两种不同的方式获取指向结构的指针。虽然第一个(“Test1”)成功,但第二个在尝试输出字符串(title)时因分段错误而失败,而数字(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]
}

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

提前致谢!

4

3 回答 3

7

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

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

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

于 2013-04-19T15:21:16.617 回答
2

在本地声明的变量,也称为“自动”,通常存储在当前函数的堆栈框架中 - 这样当您从声明它们的函数返回时,它们会从堆栈中弹出,然后调用一个函数可以写在他们身上。malloc在堆上分配一定范围的内存,在您调用之前一直分配给您使用free,无论您的代码在哪个范围内。

于 2013-04-19T15:25:21.363 回答
0

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

因此,在测试 2 中,您的程序在menu->items访问showMenu().

于 2013-04-19T15:32:32.220 回答