-1

I was reading about structs in C that there are 2 ways to define a struct variable (which initializes it and creates memory for it).

EDIT: I found the answer. The reason it was not working was because the game_struct variable got destroyed as soon as the game_create function exited and then I was left with an address to a place in memory that I was not allowed to access anymore. And the reason that the malloc version worked was because it allocated memory for the struct and I passed back the value of the address.

  1. First way is to simply define it as a normal variable like this
struct Person {
    char name[50];
    int age;
    float salary;
};

int main() {
    struct Person person1, person2;

    strcpy(person1.name, "Joey Gladstone");
    person1.age = 13;
}
  1. The second way is to use malloc like this.
struct game * game_create()
{
    struct game * game;

    game = malloc(sizeof(struct game));

    return game;
}

But when I tried to use the first way in my game it showed me this error:

[1] 2640483 segmentation fault (core dumped) ./game

Here is my struct defined in game.h

#ifndef __GAME_H__
#define __GAME_H__

#include <SDL2/SDL.h>
#include <stdbool.h>

// Struct for displaying text on screen
typedef struct {
    SDL_Rect rect;
    SDL_Texture * texture;
} text;

// Ship orientation
typedef enum {
    HORIZONTAL,
    VERTICAL
} orientation;

typedef struct {
    SDL_Rect rect;
    bool is_placed;
    orientation orientation;
} ship;

typedef struct {
    SDL_Rect rect;
    bool is_hit;
} shot;

struct game {
    text title;
    SDL_Window * window;
    SDL_Renderer * renderer;
    SDL_Rect player_aim;
    shot player_shots[100];
    shot opponent_shots[100];
    ship player_ships[10];
    ship opponent_ships[10];
    bool is_running;
    int cell_size;
    int grid_width;
    int grid_height;
    int grid_offset_y;
    int placing_ship_index;
    int player_grid_offset_x;
    int opponent_grid_offset_x;
    int placed_ships;
    int player_hits;
    int opponent_hits;
    int player_shots_count;
    int opponent_shots_count;
    bool is_shooting;
};

struct game * game_create();
void game_run(struct game * game);
void game_init(struct game * game);
int game_terminate(struct game * game);
void game_quit(struct game * game);
text game_get_title(struct game * game);

#endif

And this is how I try to create the struct variable:

#include "include/game.h"

struct game * game_create()
{
    struct game game_struct;

    return &game_struct;
}

And I get segmentation fault error and I don't understand why, I think it should have worked. What am I doing wrong? It works with malloc but does not work like this.

Martin Zeltin
  • 2,496
  • 3
  • 18
  • 36
  • 1
    First, please include the [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). I can guess your problem from experience, but that shouldn't be the case. As for your question: you are used to modern languages like Java or C#, aren't you? ;) In your case the lifetime of variable ends with function, but the address to it outlives it. Thus, upon dereferencing your code probably accesses a non-existing object, see: https://stackoverflow.com/questions/22527846/scope-and-lifetime-of-local-variables-in-c – alagner Oct 27 '22 at 05:32
  • @alagner thanks, that answers my question, I did not know that `the lifetime of variable ends with function`. I would appreciate it if you posted an official answer for it. – Martin Zeltin Oct 27 '22 at 05:38
  • 1
    What compiler are you using that did not show a warning when you try to `return &game_struct;`. Even without increasing warning level GCC would issue a `warning: function returns address of local variable [-Wreturn-local-addr]` – Gerhardh Oct 27 '22 at 06:09

2 Answers2

3

In this function:

struct game * game_create()
{
    struct game game_struct;
    return &game_struct; // wrong!
}

The lifetime of game_struct ends at the end of the function scope, because it is a local variable created on the stack. It is cleared from the stack when the function returns.

If you want it to outlive the functions lifetime, you should create it on the heap using malloc as in your example above. Don't forget to free when you are done with it.

See: storage durations of variables in C.

  • Thank you, this is what I was missing in my understanding. – Martin Zeltin Oct 27 '22 at 05:54
  • 1
    Note (what is not your fault), StackOverflow readers sometimes only see code. Your post might get misread by very fast/lazy readers, leaving them with the impression "That is not a solution!". Not your fault, but you might represent within the code (e.g. comments or function name), that it is not the solution. Your answer otherwise is sound. – Yunnosch Oct 27 '22 at 06:00
1
#include "include/game.h"

struct game * game_create()
{
   struct game game_struct;

   return &game_struct;
}

game_struct is released as a local variable when game_create returns;

If game exists as a singleton in your application.The following modifications can be used

#include "include/game.h"

struct game * game_create()
{
   static struct game game_struct;

   return &game_struct;
}
/************************/
#include "include/game.h"
static struct game g_game_struct;
struct game * game_create()
{
   return &g_game_struct;
}

Otherwise, use malloc

liu zj
  • 25
  • 5