C中的SDL 1.2:变量不应该变化

时间:2014-10-04 18:33:51

标签: c

嗯,据我所知,它不应该 。我先提供上下文。 我想将“控件”定义为基本上是屏幕小部件:

typedef struct {
    struct Control** children;
    SDL_Surface* surface;
    struct Control* parent;
    char* type;
    int width;
    int height;
    int x;
    int y;
} Control;

主屏幕称为Window,我为它创建了一个特殊的init函数:

Control* createWindow() {
    Control window = {
        .type = "window",
        .surface = SDL_SetVideoMode(WIN_W, WIN_H, 24, SDL_SWSURFACE),
        .height = WIN_H,
        .width = WIN_W,
        .x = 0,
        .y = 0
    };
    return &window;
}

它有一个名为Panel的子项,它有自己的初始值设定项:

Control* createPanel(const char* filepath, Control* parent, int x, int y, int numberOfChildren) {
    Control panel = {
        .parent = parent,
        .children = (Control**)malloc(numberOfChildren * sizeof(Control*)),
        .type = "panel",
        .x = x,
        .y = y,
        .surface = SDL_LoadBMP(filepath)
    };
    return &panel;
}

主要功能的开头:

int main(int argc, char* args[]) {

    Control* window = NULL;
    Control* panel = NULL;

    SDL_Init(SDL_INIT_EVERYTHING);

    window = createWindow();
    panel = createPanel("BACKGROUND.bmp", window, 0, 0, 3);

现在,当到达createWindow()函数时,一切正常,window定义良好。在下一行之后,面板初始化window被破坏。我只是想不通为什么。

我认为可能是因为我发送了window作为panel的父级,因此我尝试了不通过它并删除了该任务。不行,在createPanel()返回后,它仍会混淆主范围中window的字段。

我已经调试了这个问题很长一段时间了,我就没有任何线索了。我对C很新,指针异常可能发生,我不知道,所以我真的希望这是一件非常简单的事情。

感谢您的时间。

3 个答案:

答案 0 :(得分:4)

为什么不简单:

void createWindow(Control * c) {
    *c = {
        .type = "window",
        .surface = SDL_SetVideoMode(WIN_W, WIN_H, 24, SDL_SWSURFACE),
        .height = WIN_H,
        .width = WIN_W,
        .x = 0,
        .y = 0
    };
}

然后:

Control c;
createWindow(&c); 

这样你就可以在调用位置为对象分配空间并将其地址传递给函数来初始化该地址,这实际上是RVO的手工实现,编译器很可能足够智能并且弄清楚指针指向堆栈对象,并在不调用函数的情况下直接初始化数据。

引用堆栈上的内存以使用其函数已经返回的对象是一个非常糟糕的主意。那些数据可能会“保持一段时间”,但当堆栈再次达到该深度时,数据将被覆盖,下次您将获得和/或制造垃圾。您还可以动态分配内存并返回指针,WHILE记住在调用位置处理数据或依赖其他一些管理方案,但这样做会有点过头,只需要很小的开销就可以避免。< / p>

全局对你的问题来说是一个相当笨拙的解决方案,而且毫无意义。如果您决定使用多个窗口,是否要编辑源并重新编译以在每次需要时添加另一个全局?似乎不是一个好主意。

编辑:我没有在发布之前测试该代码,假设它可以工作,但似乎指定的初始化程序不能使用解引用的指针。将初始化程序转换为类型的方法与注释中所述的一样,并且编译器生成的代码应该与初始化“程序性”相同,即c->type = "window"等等,这是我个人所做的。

答案 1 :(得分:2)

您正在返回指向局部变量的指针。你必须记住(非静态)局部变量超出范围,并且当它们被定义的函数返回时不再存在。

返回并使用此指针将导致undefined behavior,这就是您所看到的。

我建议如何解决问题?不要返回指针,返回副本


如果您迫切需要返回一个指针,而该指针在该函数中并不需要执行,则必须使用malloc分配堆。请记住,您必须free

答案 2 :(得分:1)

让我们来看看你的CreateWindow函数。

Control* createWindow() {
    Control window = {
        .type = "window",
        .surface = SDL_SetVideoMode(WIN_W, WIN_H, 24, SDL_SWSURFACE),
        .height = WIN_H,
        .width = WIN_W,
        .x = 0,
        .y = 0
    };
    return &window;
}

您正在堆栈上创建一个新的Control结构,稍后返回该地址。由于结构不在堆上,因此可能会修改该位置的数据。您希望在堆上保存窗口。

看一下这个答案:Creating a struct on the heap?