Reputation: 3295
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(¤t_location);
display_player(¤t_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
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 const
s from location
structure or you can do it like this:
memcpy(¤t_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