Pointer to struct within different struct. C - c

I am currently working on a text based game in C and I'm having a problem altering values when certain events happen. Here is some of my data structure code:
typedef struct player {
int maxhealth;
int curhealth;
int in_combat;
monster c_enemy;
char *class;
char *condition;
rooms c_room;
inventory i;
stats stats;
} player;
Now, I think my problem is that I currently have c_room (Current Room) as a rooms, instead of a pointer to a rooms. This affects me later because I need to alter things like n_monsters within the struct rooms for the current room. However, when I modify it by doing p.c_rooms.n_monsters -= 1; I'm not sure it alters the actual value of n_monsters for the room that I should be referring to. I've tested this by leaving a room when n_monsters is 0, and then coming back to see that it's back at 1, the default value.
So yea, how would I point to right room?
Just:
typedef struct player {
int maxhealth;
int curhealth;
int in_combat;
monster c_enemy;
char *class;
char *condition;
rooms *c_room; // Like this?
inventory i;
stats stats;
} player;
// And then the assignment would look like:
c_room = *rooms[3]; <- an array of rooms for the dungeon in the game.

Assuming that c_room is a plain struct and not a pointer then you are right.
If you have
struct A {
int v;
};
struct B {
struct A a;
}
A a;
a.v = 3;
B b;
b.a = a;
This will actually copy the content of a inside B.a since they are assigned by value. They will be two different A, any modification to one of them won't be reflected on the other.
In your situation I would do something like:
struct Room {
// whatever
}
struct Room rooms[MAX_ROOMS];
struct Player {
struct Room *room;
}
Player p;
p.room = &rooms[index];
Now you will be able to correctly reference to room by p->room, it will be just a pointer to the actual room.

Related

Accessing and changing variables from a struct in a struct with pointers

Tearing my hair out on this one.
So I have 2 structs:
struct character_data{
(a billion other varibles);
struct skill_stuff *skillstats;
};
struct skill_stuff{
int skill;
int skillname;
};
My problem is, I'm trying to access data in *skillstats, but I crash every time.
void this_skill(character_data ch){
int skill = 1;
ch->skillstats->skill = skill;
}
Even trying to just access it in a print function, using ("%d", ch->skillstats->skill) crashes it. I'm at my wit's end.

Structures in C with "no member named..." error

I'm trying to create a struct which contains the country, state, city and the name of a local shop. Unfortunately, I get this error:
No member named bavaria in struct country
So it seems that the error occurs here:
strcpy(germany.bavaria.ingolstadt.westpark, "Westpark");
What am I doing wrong?
This is my complete code:
#include <stdio.h>
#include <string.h>
int main() {
struct country {
char countryname[100];
struct state {
char statename[100];
struct city {
char cityname[100];
int postal;
struct shop {
char shopname[100];
} shop;
} city;
} state;
} country;
struct country germany;
struct state bavaria;
struct city ingolstadt;
struct shop westpark;
strcpy(germany.countryname, "Germany");
strcpy(germany.bavaria.ingolstadt.westpark, "Westpark");
return 0;
}
Let's separate the definitions out from where they're used to make it easier to read:
struct shop {
char shopname[100];
};
struct city {
char cityname[100];
int postal;
struct shop shop;
};
struct state {
char statename[100];
struct city city;
};
struct country {
char countryname[100];
struct state state;
};
Now you have:
struct country germany;
struct state bavaria;
struct city ingolstadt;
struct shop westpark;
strcpy(germany.bavaria.ingolstadt.westpark, "Westpark");
Here's the issue: struct country does not have a member called bavaria. It only has a member called state. What you want is:
strcpy(germany.state.city.shop.shopname, "Westpark");
What you probably really want is this:
struct country germany;
strcpy(germany.countryname, "Germany");
strcpy(germany.state.statename, "Bavaria");
strcpy(germany.state.city.cityname, "Ingolstadt");
strcpy(germany.state.city.shop.shopname, "Westpark");
When you write struct Y in this context
struct X {
struct Y {
int z;
} y;
} x;
you do two things:
Define struct Y, and
Add field y of type struct Y inside struct X.
The four structs that you define are independent of each other. Each of your structs defines a single shop, because there are no collections inside your struct country.
Here is how you can define your shop using the structures that you defined:
// This is what the structure dictates, probably not what you want
struct country westpark;
strcpy(westpark.countryname, "Germany");
strcpy(westpark.state.statename, "Bavaria");
strcpy(westpark.state.city.cityname, "Ingolstadt");
strcpy(westpark.state.city.shop.shopname, "Westpark");
This does not look like anything that you may want, though. I think you were looking for something like this:
struct country {
char countryname[100];
struct state {
char statename[100];
struct city {
char cityname[100];
int postal;
struct shop {
char shopname[100];
} shop[MAX_SHOP]; // maybe 128
int shopCount;
} city[MAX_CITY]; // Around 256
int cityCount;
} state[MAX_STATE]; // Probably 16
int stateCount;
} country;
The idea here is to construct a country as an array of states, a state as an array of cities, and a city as an array of shops. Each level of this hierarchy also stores a count of items in its level, i.e. stateCount counts how many elements of the state[] array have been filled, cityCount in each state[] stores the number of city[] elements that have been filled, and so on.
The size of this struct is going to be about 50MB, so do not make it an automatic local variable: it should be either an outer scope-static or a function-scope static, because 50 MB is too much of a stack space on most systems. Here is how you would add your shop to this struct:
strcpy(country.countryname, "Germany");
country.stateCount = 1; // For Bavaria
strcpy(country.state[0].statename, "Bavaria");
country.state[0].cityCount = 1; // For Ingolstadt
strcpy(country.state[0].city[0].cityname, "Ingolstadt");
country.state[0].city[0].shopCount = 1; // for Westpark
strcpy(country.state[0].city[0].shop[0].shopname, "Westpark");
Note that this is extremely inefficient, because it pre-allocates everything at the max. Hence the elements of the state[] array representing Bremen and Bavaria would end up with the same number of pre-allocated city[] elements, even though Bavaria is a lot larger, and probably needs more city entries. To deal with this in a resource-efficient way you would need to use dynamic memory allocation.
The variables bavaria, ingolstadt, and westpark are separate items, not members of the country struct.
strcpy(germany.state.city.shop.shopname, "Westpark");
might work (but perhaps not do what you intend).
Based on how your struct is currently defined, you would need to do this:
strcpy(germany.countryname, "Germany");
strcpy(germany.state.statename, "Bavaria");
strcpy(germany.state.city.cityname, "ingolstadt");
strcpy(germany.state.city.shop.shopname, "Westpark");
A better way to define the struct would be like this:
struct shop {
char countryname[100];
char statename[100];
char cityname[100];
int postal;
char shopname[100];
};
Then you could do this:
struct shop myshop;
strcpy(myshop.countryname, "Germany");
strcpy(myshop.statename, "Bavaria");
strcpy(myshop.cityname, "ingolstadt");
strcpy(myshop.shopname, "Westpark");
You have defined four independent structs. They are not linked with each other.
You now can do
strcpy(germany.state.city.shop, "Westpark");
or
strcpy(westpark, "Westpark");
In general, struct member names are compile time things. They are resolved to address offsets by the compiler. You city/state/shop names are runtime data. You cannot use them as struct members.
Also you apparently want to model a 1:n relation. I think you need a different data structure, like e.g. a hash.

Expected specifier-qualifier-list before 'rooms'

I'm working on a DnD-Text-Based-Style C game, and I'm having a problem compiling my structure.
Here is what I have for a structure so far:
typedef struct stats { //
int strength; //
int wisdom; //
int agility; //
} stats;
typedef struct rooms {
int n_monsters;
int visited;
rooms nentry;
rooms sentry;
rooms wentry;
rooms eentry;
monster *monsters;
} rooms;
typedef struct monster {
int difficulty;
char *name;
char *type;
int hp;
} monster;
typedef struct dungeon {
char *name;
int n_rooms;
rooms *rooms;
} dungeon;
typedef struct player {
int maxhealth;
int curhealth;
int mana;
char *class;
char *condition;
stats stats;
rooms c_room;
} player;
typedef struct game_structure {
player p1;
dungeon d;
} game_structure;
When I compile it, I get the error:
structure.h:21: error: specifier-qualifier-list before 'rooms'
Can you help me figure out why this is? Is it because I'm calling rooms from the structure that contains rooms? Please help.
There are many many problems with this piece of code. The first is that a struct definition must know how much memory to allocate, and it cannot do this when it contains a type that has not been fully defined (this is why people recommend that you use a pointer, since the size of a pointer is known at compile time).
However, and this is important, simply changing to pointers will not solve the problem, since the first room* is encountered before the appropriate typedef completes. You would need to write something like:
struct rooms {
int n_monsters;
int visited;
struct rooms *nentry;
struct rooms *sentry;
struct rooms *wentry;
struct rooms *eentry;
monster *monsters;
} rooms;
or perform a forward declaration (typedef struct rooms rooms;). You also need to make sure the monster type is defined or at least has a forward declaration.
You can't have a variable with the same name as a type. Your dungeon structure has this field entry:
rooms *rooms;
Change that variable name (or, alternatively, rename the type) to something else. What you have now is analogous to:
int int;
Which is clearly not going to work!
typedef struct rooms {
int n_monsters;
int visited;
rooms nentry;
rooms sentry;
rooms wentry;
rooms eentry;
monster *monsters;
} rooms;
Looks like rooms is a recursive type, you certainly wanted to use pointers instead:
typedef struct rooms rooms;
struct rooms {
int n_monsters;
int visited;
rooms *nentry;
rooms *sentry;
rooms *wentry;
rooms *eentry;
monster *monsters;
} rooms;

Assigning Array of Structs to a typedef struct

How do I assign to a typedef struct an array of another struct with a similar structure.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int age;
int height;
} Person[3];
struct internalStruct {
int age;
int height;
};
int main(void) {
//Possible
Person bob = {{7,5},{4,2},{4,3}};
//Is it possible to assign array to struct?
struct internalStruct intr[3] = {{4,32},{2,4},{2,4}};
Person job = intr; // Does not work :(.
printf("%d", jon[0].height);
return 0;
}
You cannot assign to an array in C. You can initialize an array when you declare it, but an array expression cannot appear on the left side of an assignment operator.
If you want to copy the value of an array object into another array object, you can use an explicit loop to assign each element (assuming the element type is assignable), or you can use memcpy(). (Note that a call to memcpy() needs to specify the number of bytes to copy; use sizeof for this.)
And your typedef Person:
typedef struct {
int age;
int height;
} Person[3];
is ill-advised. A Person object (variable) isn't a person; it's an array of 3 persons (people?).
My advice: Drop the typedef and just use a struct tag (as you already do for struct internalStruct) and don't try to create a special name for the array type:
struct Person {
int age;
int height;
};
...
struct Person bob[] = {{7,5},{4,2},{4,3}};
(This is still confusing, since bob is three people.)
And struct Person (as I've defined it here) and struct internalStruct are two distinct types. If you're trying to assign between these two types, it probably indicates a design flaw in your code; objects you're assigning to each other should be of the same type.
Recommended reading: the comp.lang.c FAQ, especially section 6 (arrays and pointers).
I would not suggest this tough, since you might run into memory leaks when the two structs are different:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int age;
int height;
} Person[3];
struct internalStruct {
int age;
int height;
};
int main(void) {
//Possible
Person bob = {{7,5},{4,2},{4,3}};
//Is it possible to assign array to struct?
struct internalStruct intr[3] = {{4,32},{2,4},{2,4}};
Person* jon= (Person *)intr; // Does not work :(.
printf("%d", jon[0]->height);
return 0;
}
Your Person type is an array of three structures, each of which is similar to your struct internalStruct. So, you can't just assign a struct internalStruct to a Person, though you can (with some help) assign it to one of the elements of a Person.
Also, copying arrays in C requires copying element by element, or copying the block of memory with a function like memcpy().
So the simplest way to do this would be to define struct internalStruct before Person, and define Person in terms of struct internalStruct:
struct internalStruct {
int age;
int height;
};
typedef struct internalStruct Person[3];
Doing it this way makes it possible to assign a struct internalStruct to an element of Person without type mismatches. For example:
struct internalStruct s1 = {4,32},
s2 = {2,4},
s3 = {2,4};
Person jon;
jon[0] = s1;
jon[1] = s2;
jon[2] = s3;
If you have an array of three struct internalStructs, you could copy it with a loop:
struct internalStruct st[3] = { {4,32}, {2,4}, {2,4} };
Person jon;
for (int i = 0; i < 3; i++)
jon[i] = st[i];
If you don't want to define Person in terms of struct internalStruct, then you have to make some assumptions, like that the layout of the two structures will be identical. If so, you could copy with memcpy():
struct internalStruct intr[3] = { {4,32}, {2,4}, {2,4} };
Person jon;
memcpy(jon, intr, sizeof(Person));

Best way to handle array nested structs in C

Hey everyone, I've been having some trouble in C, i'm using a variety of array nested structs in order to model a universe. Here is the struct code...
struct star
{
int x;
int y;
int z;
int m;
char name[100];
};
struct colony
{
int pop;
};
struct planet
{
int x;
int y;
int z;
int m;
int colonized;
char name[100];
struct colony colony_member;
};
struct galaxy
{
int x;
int y;
int z;
char name[100];
struct planet planet_member;
struct star star_member;
};
Let's say I made 10 random galaxies with random values in the struct, how would I create 100 planets within that galaxy struct? I'm confused as how the best way to handle this would be, or even if structs if the way I want to go.
Thanks in advance!
-Devan
You can create a pointer and allow varied number of planets and stars to your galaxy!
struct galaxy
{
int x;
int y;
int z;
char name[100];
struct planet *planet_member;
struct star *star_member;
};
You have several options available, starting with the easiest:
struct galaxy
{
int x;
int y;
int z;
char name[100];
int number_of_planets;
struct planet *planet_member; // a pointer!
struct star star_member;
};
and to create a galaxy:
galaxy g;
g.number_of_planets = some_random_value
g.planet_member = malloc (sizeof (planet) * g.number_of_planets);
for (i = 0 ; i < g.number_of_planets ; ++i)
{
g.planet_member [i].x = something
g.planet_member [i].y = something
g.planet_member [i].z = something
// and so on for each planet
}
Don't forget, you need to free the memory you malloc, otherwise you'll get a memory leak.
You could use more complex data structures, like a linked list. So, your galaxy struct has a pointer to the first and last planet in the list. Each planet has a pointer to the next and previous planet in the list. So starting with the first planet and reading the next planet pointer you can process each planet in the list. Look up linked list on Google to find more information about it. It's a lot more work, and work that's been done many times already, which leads to....
...progressing to C++ where there's a standard library that can do all the fiddly housekeeping of linked lists and other data types for you. So, your structure would become:
struct galaxy
{
int x;
int y;
int z;
std::string name;
std::vector <struct planet> planets; // vector is an array like type
std::list <star> stars; // list is a linked list
};
But, you could go further still and make galaxy a C++ class so that when you create one, it automatically creates the planets and stars in it, and when you get free it, the class automatically frees all the planets and stars it holds.

Resources