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

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.

Related

Does multiple struct (Nested structure) exist in C?

I wonder if there is a way to declare multiple structs in C.
For example, I made this:
struct Team{
char TeamName[20];
int Point;
int Goals;
};
typedef struct TeamCup {
char GroupID;
struct Team team;
}Group;
Group g1, g2;
I want each TeamCup to have 4 teams. But when it comes to input process, in my loop, the variable here is undefined:
g1.Team[i].Point;
I want each TeamCup to have 4 teams
In this case you need to write
typedef struct TeamCup {
char GroupID;
struct Team team[4];
}Group;
and
g1.team[i].Point;
Thar is you need to declare an array of objects of the type struct Team within the structure struct TeamCup.

Returning a nested structure from a function

I am writing code in which I want to return a nested structure. I wonder how to do that.
static int ORDERID = 0;
struct item
{
struct data
{
int orderid;
char content[10][20];
} details;
struct node *next;
};
typedef struct item product;
So insertion of a new product contains two parts:
details structure
pointer pointing to next product
In the details structure I have to have different types of product description, say:
Shoes with its orderid, and other details in the array of strings (char content[10][10])
Shirt with its orderid, and other details in the array of strings (char content[10][10])
So for the insertion of a new product I need a function to return a details structure i.e the nested structure of the product.
How to do that?
Well, you can actually define the struct data outside of the struct item and then use struct data to define a variable details inside of struct item. That is,
struct data {
int orderid;
char content[10][20];
};
struct item {
struct data details;
struct item *next;
}
And, then you can freely return a struct data object from a function.
EDIT :
If you want to create a function which can return a struct data object you can probably do the following :-
struct data * function_data() {
struct data *someData;
someData->orderid = 16;
someData->content[0] = "Shoes";
return someData;
}
I hope this adds further quality to the answer.
You can use struct data as the return type of a function

Array of nested structures

I have huge arrays of nested structures which makes it impossible to allot that kind of space and forces me to use heap. But I am facing difficulties using malloc.
The gist of the problem is below.
struct year_of_joining
{
struct district
{
struct colleges
{
struct departments
{
struct sections
{
struct students
{
int sex;
}student[100];
}section_no[8];
}department_no[17];
}college[153];
}dist[13];
};
If I use
int main()
{
int i=0;
struct year_of_joining** year;
year = malloc(100 * sizeof(struct year_of_joining));
for (i = 0; i < 100; i++)
{
year[i] = malloc(sizeof(struct year_of_joining));
}
year[1]->dist[0].college[0].department_no[0].section_no[0].student[8].sex = 1;//works fine
printf("%d", year[1]->dist[0].college[0].department_no[0].section_no[0].student[8].sex);//prints 1
free(year);
return 0;
}
It works fine but when I create a pointer to pointer for dist like year_of_joining and use indirection operator it does not compile:
year[1]->dist[2]->college[0].department_no[0].section_no[0].student[8].sex = 9;//error C2039: 'dist' : is not a member of 'year_of_joining'
How do I solve this? Am I even on the right track?
I think you are way off track here.
Note that a single struct year_of_joining is approximately 100 MiB of data. An array of 100 such structures requires approximately 10 GiB of data (and that is only recording the sex of the students — no other information at all).
struct year_of_joining** year;
year = malloc(100 * sizeof(struct year_of_joining));
This memory allocation allocates enough space for millions of pointers. You almost certainly intended to use:
struct year_of_joining *year = malloc(100 * sizeof(struct year_of_joining));
struct year_of_joining *year = malloc(100 * sizeof(*year));
This allocates 100 years worth of the structure.
However, it seems improbable that you have 13 districts, each of which has exactly 153 colleges, each college having exactly 17 departments, each of which has 8 sections, with each section having exactly 100 students. That corresponds to over 25 million students every year!
You are going to need a vastly more flexible arrangement, where each of the structures contains a pointer to a list of the nested structures, so you can have bigger sections but smaller colleges, etc. It will need to work more along the lines of:
struct students
{
char name[32];
int sex;
// ... and other data ...
};
struct sections
{
char name[32];
// ... and other data ...
int n_students;
struct students *students;
};
struct departments
{
char name[32];
int n_sections;
struct sections *sections;
}
struct colleges
{
char name[32];
// ... and other data ...
int n_departments;
struct departments *departments;
};
struct district
{
char name[32];
// ... and other data ..
int n_colleges;
struct college *colleges;
};
struct year_of_joining
{
int year;
// ... and other data ...
int n_districts;
struct district *districts;
};
Even that feels not entirely correct, but it would be a better way of organizing the data than the original, if only because if a department only has one section and enrolls only ten students (because it is a minority-interest department), then it allocates only enough space for one section and ten students, rather than allocating space for 800 students and 8 sections.
You are not on the right track. Your struct is really huge, and you will need to recompile your program if the size of your input (e.g. number of students) ever gets too big.
I suggest you model your data as smaller structs that can be individually allocated, perhaps using pointers or ID numbers to link them together.
Another language like Ruby might be a better choice than C, allowing you to focus more on your data than on the details of its storage in memory. In general, C is good for fast, low-level interactions with the operating system, while languages with garbage compilers and dynamic typing will be much easier for writing reports and aggregating data.
Anyway, suppose you want to use C. The data structure you choose will depend on several things. What is the precise real-world structure of the data you are modelling? What performance characteristics do you need? Does it need to be fast to add things, or fast to extract certain statistics from the data? Without knowing that answers to these questions, it is hard for us to come up with a usable answer for your application. But Jonathan Leffler has taken a good guess. Here is my guess:
#include <stdint.h>
struct student
{
char * name;
uint32_t sex;
uint32_t year_of_joining;
// Index into an array of sections.
// You could also use a pointer to a section (section *)
// but the pointer would become invalid if you ever moved the
// sections in memory (e.g. by calling realloc on an array
// of sections).
uint32_t section_id;
};
struct section
{
char * name;
uint32_t department_id;
};
struct department
{
char * name;
uint32_t college_id;
};
struct college
{
char * name;
uint32_t district_id;
};
struct district
{
char * name;
};
// These typedefs make it so we don't have to
// write "struct" when using the structs.
typedef struct student student;
typedef struct section section;
typedef struct department department;
typedef struct college college;
typedef struct district district;
// Dynamically sized arrays for holding things.
student * student_array;
section * section_array;
department * department_array;
college * college_array;
district * district_array;

Function to compare structures in order to sort a list

I have an abstract data type in C, LIST OF THINGS, ist node has a void* pointer, what i'm trying to do is create a function to compare an specific field of different structures in order to sort my list of things.
typedef struct node{
char *name;
void *thing;
struct node *next;
}Node;
This is the node i'm working with, i've already created a list of integers, list of structures and te compare function for both, but i can't figure out how to do a compare function to diferent structures. for example:
given these types:
typedef struct main{
float weight;
char*model;
float maxspeed;
}Main;
typedef struct airplane{
float weight;
float maxspeed;
}Airplane;
typedef struct car{
char*model;
float maxspeed;
}Car;
And this is the function, so you have an idea of what i'm trying to do, it doesn't work, Main has fields that doesn't exist in either one or the other structure.
int comparefunction(void*a,void*b){
Main a1, a2;
a1=*(Main*)a;
a2=*(Main*)b;
return a1.weight-a2.weight;
}
This function(doesn't work) is passed as a paremeter to the function that links the nodes in order to use the comparefunction.
//insert prototype:
//insert(Node*listp,Node*newp,int(*func_comp)(void*,void*));
list=insert(list,newItem(&car1),comparefunction);
list=insert(list,newItem(&airplane1),comparefunction);
list=insert(list,newItem(&airplane2),comparefunction);
How can i do to compare a single field of two or more different structures? assuming that i know what each structure contains
If you're trying to compare somewhat similar things, you can look into unions.
struct attributes{
float weight;
// other common things?
};
struct thing {
enum { Car, Main, Airplane } type;
struct attributes attrs;
union {
struct Car car;
struct Main main;
struct Airplane airplane;
} other_thing;
};
You'd change your list to store the thing struct, which is a structure that encapsulates all your possible types. The common elements of each type are extracted to the attributes struct. Your compare function would then operate on the attributes struct of the thing struct. The union is used here to only create enough space within struct thing for the largest of the union elements, so that you're not wasting space storing all three structs and only using one.
Well, your car struct doesn't have a weight field, so I'm not exactly sure what you're trying to accomplish here. If you had your car struct look like
typedef struct car {
float weight;
char* model;
float maxspeed;
} Car;
I think your function would work. Note, it is important that the member that you want to compare is at the same offset into each struct including the Main struct.
EDIT
This does work.
Another edit based on comments
You can't compare two completely unrelated things. This is not a technical deficiency with C. It just does not logically make any sense to compare for example an Airplane and an int.

Pointer to struct within different struct. 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.

Resources