MalphasWats
MalphasWats

Reputation: 3295

Working with C Structures

I'm developing some code for a small gaming device I've designed. I've got completely stuck trying to build what is ultimately a Graph of map locations.

I have 2 structs:

typedef struct point {
    int x;
    int y;
} point;


typedef struct location {
    const point portal_in;
    const point portal_out;

    const byte *map;
    const byte width;
    const byte height;

    struct location *portals[8];

    point player;

    struct location *return_to;
} location;

Each location has a list of other locations that it links to, as well as the location it links from.

I tried to set up the locations like this:

location build_locations()
{
    location village = { 
        .portal_in={15, 14}, 
        .portal_out={0, 0}, 
        .map=&VILLAGE[0],
        .width=32,
        .height=16,
        .player={15, 14}, 
        .return_to=0 
    };
    location loc = { 
        .portal_in={8, 7}, 
        .portal_out={11, 10}, 
        .map=&HOUSE[0],
        .width=8,
        .height=8,
        .player={0, 0}, 
        .return_to=&village
    };

    village.portals[0] = &loc;

    return village;
}

this gets called in my main() function:

location current_location = build_locations();

And this works, up to a point - I can draw the village map and move the player around it:

display_map(&current_location);

display_player(&current_location);

and so on. The trouble comes when I want to swap into a new location.

If I try and reassign current_location, I get a compiler error complaining about assignment to read only variable:

current_location = current_location.portals[0];

This is easily the most complex code I've written in C, so I know I'm out of my depth when it comes to structures and pointers, but I'm trying to learn and I've come a long way already.

Is there a better way to do what I'm trying to do? Or is there something obvious I have missed?

Thanks

EDIT:

This is the most minimal example I can come up with:

typedef unsigned char byte;

static const byte VILLAGE[] = {
      0,   0,   0,   0,  175, 181, 181, 181, 181, 181, 181, 175,   0,   0,   0,   0,
      /// And so on - indices of tiles defined elsewhere but irrelevant here
};

static const byte HOUSE[] = {
      0,   0,   0,   0,  175, 181, 181, 181, 181, 181, 181, 175,   0,   0,   0,   0,
      /// And so on - indices of tiles defined elsewhere but irrelevant here
};

typedef struct point {
    int x;
    int y;
} point;


typedef struct location {
    const point portal_in;
    const point portal_out;

    const byte *map;
    const byte width;
    const byte height;

    struct location *portals[8];

    point player;

    struct location *return_to;
} location; 

location build_locations()
{
    location village = { 
        .portal_in={15, 14}, 
        .portal_out={0, 0}, 
        .map=&VILLAGE[0],
        .width=32,
        .height=16,
        .player={15, 14}, 
        .return_to=0 
    };
    location loc = { 
        .portal_in={8, 7}, 
        .portal_out={11, 10}, 
        .map=&HOUSE[0],
        .width=8,
        .height=8,
        .player={0, 0}, 
        .return_to=&village
    };

    village.portals[0] = &loc;

    return village;
}

int main(void)
{
    location current_location = build_locations();

    if (current_location.player.x == 5 && current_location.player.y == 4)
    {
        current_location = current_location.portals[0];
    }
}

Upvotes: 0

Views: 85

Answers (1)

Afshin
Afshin

Reputation: 9173

Runtime problem:

Problem is simple. Both village and loc are on stack.

on return, you get a copy of village, but no copy for loc. so loc will be released after return. You can use a code like this to solve your problem:

village.portals[0] = calloc(1, sizeof(*(village.portals[0])));
memcpy(&village.portals[0], &loc, sizeof(loc)); //->or just assign village.portals[0] directly

Update:

Compile problem

Yea comments on current_location is correct too. You can solve it like this:

current_location = *(current_location.portals[0]);

or use pointers completely for accessing data.

But just remember runtime problem that I mentioned is very important and very hard to trace later too.

Update 2:

I just noticed that you have const members in your structure. that's why you get those read-only errors if you use assignment only. You can solve this problem by removing those consts from location structure or you can do it like this:

memcpy(&current_location, current_location.portals[0], sizeof(current_location));

but I don't suggest this approach, it is better to use pointers to prevent this problem.

Upvotes: 1

Related Questions