0

I've been making a game in SDL, in order to minimize the amount of spaghetti-code present, i've been making my own functions to automate many SDL processes, one of which is a function to allocate a picture or font to a texture.

Problem is that after the end of function, the SDL_Texture variable doesn't work anymore.

I've been able to replicate the problem scaling it down to a 'test' program.

Code:

void func(SDL_Texture* pText, SDL_Rect* pRect, SDL_Renderer* rend){
    SDL_Surface* loadSurface = IMG_Load("pic.png");
        if(!loadSurface)
            printf("Error creating surface. - %s", SDL_GetError());

    pText = SDL_CreateTextureFromSurface(rend, loadSurface);
        if(!pText)
            printf("Error creating texture. - %s", SDL_GetError());

    SDL_FreeSurface(loadSurface);
}

int main(){
    SDL_Renderer* rend;
    SDL_Texture* pText;
    SDL_Rect pRect;

    if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER) != 0){
        printf("error initializing SDL: %s\n", SDL_GetError());
        return 1;
    }
    SDL_Window* win = SDL_CreateWindow("app", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 250, 250, 0);
    rend = SDL_CreateRenderer(win, -1, SDL_RENDERER_SOFTWARE);

    func(pText, &pRect, rend); // test function

    int x, y;
    SDL_QueryTexture(pText, NULL, NULL, &x, &y); //Get texture size (program will either crash or print nonsense values.)

    printf("C: %d, y: %d\n", x, y);
    printf("Hang in there...");

    return 0;
}

Compiled with G++, SDL2 dynamic (using .dll and .so)

genpfault
  • 51,148
  • 11
  • 85
  • 139
  • 1
    You seem to have forgotten that by default arguments to functions are passes *by value*. Meaning the value used in the call is copied into the functions local argument variable. And as any other local variable, the life-time of argument variables will end when the function ends. For your specific case, the assignment to `pText` you do inside `func` will be lost once `func` returns. The `pText` pointer in the `main` function will still have an *indeterminate* value, and using it will lead to *undefined behavior* and your subsequent crash. – Some programmer dude Aug 29 '23 at 18:08
  • And are you sure you're programming in C++? There's nothing in that code that is specific to C++. It could all be a plain C program. Unfortunately, you will have the same problem with C, but in a different form. Using indeterminate values (like that of `pText`) in itself isn't directly undefined behavior in C. But dereference a pointer that is indeterminate is. – Some programmer dude Aug 29 '23 at 18:10
  • *I've been able to replicate the problem scaling it down to a 'test' program.* -- And [here is the same issue](https://godbolt.org/z/vMbzf5v6T). Fix the issue at the link, and apply similar changes to your program. – PaulMcKenzie Aug 29 '23 at 18:36
  • @Someprogrammerdude How's it just passing the value of SDL_Texture? It passes a pointer to it, thus it should pass the address to the lifelong variable. 2 This is C code, but it does the same exact thing with the C++ version of it, – nyedoardo Aug 29 '23 at 18:37
  • You know SDL2_Image has [`IMG_LoadTexture`](https://wiki.libsdl.org/SDL2_image/IMG_LoadTexture), right? – Nelfeal Aug 30 '23 at 10:39

1 Answers1

0

Edit:

Found a solution, problem was that by passing SDL_Texture* the address the pointer was pointing to won't be modified, which is what we actually need. To fix this I just passed SDL_Texture** and &pText to the function.

void func(SDL_Texture** pText, SDL_Rect* pRect, SDL_Renderer* rend){
    SDL_Surface* loadSurface = IMG_Load("pic.png");
        if(!loadSurface)
            printf("Error creating surface. - %s", SDL_GetError());

    *pText = SDL_CreateTextureFromSurface(rend, loadSurface);
        if(!pText)
            printf("Error creating texture. - %s", SDL_GetError());

    SDL_FreeSurface(loadSurface);
}

int main(){
    SDL_Renderer* rend;
    SDL_Texture* pText;
    SDL_Rect pRect;

    if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER) != 0){
        printf("error initializing SDL: %s\n", SDL_GetError());
        return 1;
    }
    SDL_Window* win = SDL_CreateWindow("app", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 250, 250, 0);
    rend = SDL_CreateRenderer(win, -1, SDL_RENDERER_SOFTWARE);

    func(&pText, &pRect, rend); // test function

    int x, y;
    SDL_QueryTexture(pText, NULL, NULL, &x, &y); //Get texture size (now works)

    printf("C: %d, y: %d\n", x, y);
    printf("Hang in there...");

    return 0;
}
  • 2
    What resources are you using to learn C++? Because the change is very C-specific, *emulating* pass by reference. Which is not needed in C++, as C++ have syntax for references. I really think you need to take a step back and think about your learning resources. – Some programmer dude Aug 29 '23 at 20:46
  • 1
    @Someprogrammerdude In this case you probably just want a return value. – Nelfeal Aug 30 '23 at 10:40