Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c

struct

strcpy

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;
}
like image 206
PeterPan Avatar asked Mar 15 '23 18:03

PeterPan


2 Answers

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");
like image 197
Claudiu Avatar answered Mar 24 '23 07:03

Claudiu


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.

like image 42
Sergey Kalinichenko Avatar answered Mar 24 '23 07:03

Sergey Kalinichenko