4

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;
}
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
PeterPan
  • 684
  • 1
  • 10
  • 27

5 Answers5

3

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");
Claudiu
  • 224,032
  • 165
  • 485
  • 680
1

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.

undur_gongor
  • 15,657
  • 5
  • 63
  • 75
  • What do you mean with a 1:n relation? – PeterPan Sep 17 '15 at 13:48
  • 1
    I guess you want to have one data object per country. This one data object shall be linked to several ("n") state data objects. Each of these state object shall be linked to several cities and so on. You could achieve this with one huge struct containing arrays as described in dasblinkenlight's answer. Then you cannot easily/quickly lookup by e.g. state name. Or you create hashes... – undur_gongor Sep 17 '15 at 13:55
  • Thanks for the answer! – PeterPan Sep 17 '15 at 13:57
1

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).

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
1

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");
dbush
  • 205,898
  • 23
  • 218
  • 273
1

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.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Thanks for that detailed explanation! You deserve way more than one +1 for that. Last question: for what is `stateCount`, `cityCount` and `shopCount` necessary? 'Just' for readability and to know how many values are saved? – PeterPan Sep 17 '15 at 15:01
  • 1
    @S.Eberl Counts are not just for readability. Since the arrays pre-allocate equal amount of space for each state in the country, and for each city in a state, your program needs to know which array elements have actual data in them. When you fill your structure, Bavaria might have 200 cities, and Bremen might have 30 cities. If you make a loop to print out all shops by state, you need to know when the loop should end, so you would write something like this: `for (int s = 0 ; s != country.stateCount ; s++) for (int c = 0 ; c != country.state[s].cityCount ; c++) {...}` – Sergey Kalinichenko Sep 17 '15 at 15:09
  • I just played around with that a little bit today and did the mistake to make it an auto local var. By rereading your answer I remembered to put a static there. So here is my question. You said that 50 MB is too much for most stacks. Is that a bad trying? Let's say I enter a value for every array of the struct so nothing is empty. The program is going to be 'big'. Is it a problem that the program is too big for the stack? – PeterPan Sep 19 '15 at 21:52
  • 1
    @S.Eberl The problem with programs using too much stack is that they may [crash when you start them](http://stackoverflow.com/a/20253334/335858) before doing any work. – Sergey Kalinichenko Sep 19 '15 at 22:02
  • 1
    @S.Eberl `static` is one way; using `malloc` is the other way. – Sergey Kalinichenko Sep 19 '15 at 22:32
  • How do I use malloc with structures? – PeterPan Sep 20 '15 at 17:31
  • @S.Eberl `struct country *germany = malloc(sizeof(struct country));` After that use `germany->something` in place of `germany.something`. Call `free(germany)` once you are done with the variable. – Sergey Kalinichenko Sep 20 '15 at 19:59