Структуры в C без ошибки имени члена

Я пытаюсь создать структуру, содержащую страну, штат, город и название местного магазина. К сожалению, я получаю эту ошибку:

Ни один член с именем Бавария в структуре страны

Итак, похоже, что ошибка возникает здесь: strcpy(germany.bavaria.ingolstadt.westpark, "Westpark");

Что я делаю не так?

Это мой полный код:

#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;
}

person PeterPan    schedule 17.09.2015    source источник


Ответы (5)


Когда вы пишете struct Y в этом контексте

struct X {
    struct Y {
        int z;
    } y;
} x;

вы делаете две вещи:

  • Определите struct Y и
  • Добавьте поле y типа struct Y внутри struct X.

Четыре struct, которые вы определяете, не зависят друг от друга. Каждый из ваших struct определяет отдельный магазин, потому что внутри вашего struct country нет коллекций.

Вот как вы можете определить свой магазин, используя определенные вами структуры:

// 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");

Однако это не похоже на то, что вы можете захотеть. Я думаю, вы искали что-то вроде этого:

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;

Идея здесь состоит в том, чтобы построить страну как массив штатов, штат как массив городов и город как массив магазинов. Каждый уровень этой иерархии также хранит количество элементов на своем уровне, то есть stateCount подсчитывает, сколько элементов массива state[] было заполнено, cityCount в каждом state[] хранит количество city[] элементов, которые были заполнены, и так далее.

Размер этого struct будет около 50 МБ, поэтому не делайте его автоматической локальной переменной: это должна быть либо статическая внешняя область, либо статическая область действия, потому что 50 МБ — это слишком много для стека в большинстве случаев. системы. Вот как вы можете добавить свой магазин к этому 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");

Обратите внимание, что это крайне неэффективно, поскольку предварительно выделяет все по максимуму. Следовательно, элементы массива state[], представляющие Бремен и Баварию, в конечном итоге будут иметь одинаковое количество предварительно выделенных элементов city[], даже несмотря на то, что Бавария намного больше и, вероятно, нуждается в большем количестве записей городов. Чтобы справиться с этим ресурсоэффективным способом, вам необходимо использовать динамическое выделение памяти.

person Sergey Kalinichenko    schedule 17.09.2015
comment
Спасибо за такое подробное объяснение! Вы заслуживаете гораздо больше, чем один +1 за это. Последний вопрос: для чего нужны stateCount, cityCount и shopCount? «Просто» для удобства чтения и для того, чтобы узнать, сколько значений сохранено? - person PeterPan; 17.09.2015
comment
@S.Eberl Счетчики нужны не только для удобства чтения. Поскольку массивы предварительно выделяют одинаковое количество места для каждого штата в стране и для каждого города в штате, ваша программа должна знать, какие элементы массива содержат фактические данные. Когда вы заполняете свою структуру, в Баварии может быть 200 городов, а в Бремене может быть 30 городов. Если вы делаете цикл для вывода всех магазинов по штатам, вам нужно знать, когда цикл должен закончиться, поэтому вы должны написать что-то вроде этого: for (int s = 0 ; s != country.stateCount ; s++) for (int c = 0 ; c != country.state[s].cityCount ; c++) {...} - person Sergey Kalinichenko; 17.09.2015
comment
Я только что немного поиграл с этим сегодня и сделал ошибку, сделав его автоматическим локальным var. Перечитав ваш ответ, я вспомнил, что поставил там статику. Вот мой вопрос. Вы сказали, что 50 МБ слишком много для большинства стеков. Это плохая попытка? Скажем, я ввожу значение для каждого массива структуры, чтобы ничего не было пустым. Программа будет «большой». Проблема в том, что программа слишком велика для стека? - person PeterPan; 20.09.2015
comment
@S.Eberl Проблема с программами, использующими слишком большой стек, заключается в том, что они могут вылетать при запуске до выполнения какой-либо работы. - person Sergey Kalinichenko; 20.09.2015
comment
@S.Eberl static в одну сторону; использование malloc - это другой способ. - person Sergey Kalinichenko; 20.09.2015
comment
Как использовать malloc со структурами? - person PeterPan; 20.09.2015
comment
@S.Eberl struct country *germany = malloc(sizeof(struct country)); После этого используйте germany->something вместо germany.something. Вызовите free(germany), когда закончите с переменной. - person Sergey Kalinichenko; 20.09.2015

Давайте отделим определения от того места, где они используются, чтобы их было легче читать:

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;
};

Теперь у вас есть:

struct country germany;
struct state bavaria;
struct city ingolstadt;
struct shop westpark;
strcpy(germany.bavaria.ingolstadt.westpark, "Westpark");

Вот проблема: у struct country нет участника с именем bavaria. В нем есть только член по имени state. Что вы хотите:

strcpy(germany.state.city.shop.shopname, "Westpark");

То, что вы, вероятно, действительно хотите, это:

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");
person Claudiu    schedule 17.09.2015

Переменные bavaria, ingolstadt и westpark являются отдельными элементами, а не элементами структуры country.

strcpy(germany.state.city.shop.shopname, "Westpark");

может работать (но, возможно, не делать то, что вы намереваетесь).

person Bo Persson    schedule 17.09.2015

В зависимости от того, как в настоящее время определена ваша структура, вам нужно будет сделать это:

strcpy(germany.countryname, "Germany"); 
strcpy(germany.state.statename, "Bavaria");
strcpy(germany.state.city.cityname, "ingolstadt");
strcpy(germany.state.city.shop.shopname, "Westpark");

Лучший способ определить структуру был бы таким:

   struct shop {
        char countryname[100];
        char statename[100];
        char cityname[100];
        int postal;
        char shopname[100];
    };

Тогда вы можете сделать это:

struct shop myshop;

strcpy(myshop.countryname, "Germany"); 
strcpy(myshop.statename, "Bavaria");
strcpy(myshop.cityname, "ingolstadt");
strcpy(myshop.shopname, "Westpark");
person dbush    schedule 17.09.2015

Вы определили четыре независимые структуры. Они не связаны друг с другом.

Теперь вы можете сделать

strcpy(germany.state.city.shop, "Westpark");

or

strcpy(westpark, "Westpark");

В общем, имена элементов структуры — это вещи времени компиляции. Они разрешаются компилятором для адресации смещений. Ваши названия городов/штатов/магазинов являются данными времени выполнения. Вы не можете использовать их в качестве членов структуры.

Также вы, по-видимому, хотите смоделировать отношение 1: n. Я думаю, вам нужна другая структура данных, например, например. хэш.

person undur_gongor    schedule 17.09.2015
comment
Что вы имеете в виду под отношением 1:n? - person PeterPan; 17.09.2015
comment
Я думаю, вы хотите иметь один объект данных для каждой страны. Этот один объект данных должен быть связан с несколькими (n) объектами данных состояния. Каждый из этих государственных объектов должен быть привязан к нескольким городам и так далее. Вы можете добиться этого с помощью одной огромной структуры, содержащей массивы, как описано в ответе dasblinkenlight. Тогда вы не можете легко/быстро искать, например. название штата. Или вы создаете хэши... - person undur_gongor; 17.09.2015
comment
Спасибо за ответ! - person PeterPan; 17.09.2015