Как построить и управлять этой сложной структурой данных C? - PullRequest
2 голосов
/ 26 октября 2011

Я совершенно сбит с толку, как эффективно управлять (заполнять и получать доступ) следующую структуру данных в C. Для краткого описания у меня есть структура, которая содержит член другой структуры, и эта структура имеет член другого структура и пр. Примерно так:

typedef struct
{
    int num;
} D;

typedef struct
{
    D *boo;
} C;

typedef struct
{
    C *far;
} B;

typedef struct
{
    int foo;
    B *bar;
} A;

A *func() {
    A *var;
    // POPULATE var
}

int main(...) {
    A *a = func();
    // PRINTING
}

Итак, каким способом лучше управлять этой структурой данных? Я имею в виду, как я собираюсь заполнить данные для этого типизированного указателя?

Представьте, что я собираюсь напечатать все данные, которые a хранит (на // PRINTING), я думаю, у меня будет что-то вроде: a->bar->far->boo->num. Я не знаю, правильно ли это работает и, следовательно, является ли оно надежным.

Ответы [ 2 ]

3 голосов
/ 26 октября 2011

Это не будет легче, например, Python, если вы выбираете такой разрозненный дизайн, естественно, будет немного больно управлять, естественно.

Печать будет работать так, как вы говорите, оператор C -> обычно используется именно так. Конечно, если могут быть указатели NULL, где структура не является «полной», вам необходимо проверить это перед разыменованием указателя, иначе у вас будет неопределенное поведение.

Пополнение, вероятно, лучше всего сделать, написав функции для создания экземпляра на каждом слое, которые затем могут вызывать друг друга в цепочке для настройки самого верхнего типа:

D* d_create(int num);
C* c_create(int num);
B* b_create(int num);

A* a_create(int foo, int num)
{
   A* a = malloc(sizeof *a);
   if(a != NULL)
   {
     a->foo = foo;
     a->bar = b_create(num);
     if(a->bar != NULL)
       return a;
     free(a);
   }
   return NULL;
}

Это немного громоздко, поскольку все фактические данные (foo и num) должны быть переданы в функцию верхнего уровня, которая создает экземпляр A, но она работает и очень проста .

Обратите внимание, как мы отлавливаем ошибки от распределителей памяти более низкого уровня, убедившись, что указатель B не равен NULL. Такие проверки необходимы и для других create -функций.

0 голосов
/ 26 октября 2011

Невозможно ответить «как мне это сделать», не зная, почему вы решили использовать указатели. Если каждому A принадлежит свой собственный B и т. Д., Вам необходимо выделить B при выделении A и освободить его при освобождении A. Но в этом случае указатель бесполезен и создает дополнительную работу. Вы могли бы просто сделать:

typedef struct
{
    int num;
} D;

typedef struct
{
    D boo;
} C;

typedef struct
{
    C far;
} B;

typedef struct
{
    int foo;
    B bar;
} A;

A func() { // don't necessarily need to return a pointer here either
    A var;
    var.foo = 1;
    var.bar.far.boo.num = 2;
    return var;
}

Если причина указателя в том, что у вас может быть несколько экземпляров A, которые все указывают на один и тот же экземпляр B, то вам нужно решить, как вы будете знать, когда этот экземпляр B не является дольше в использовании и может быть освобожден. Существуют решения общего назначения, такие как подсчет ссылок, или может быть что-то конкретное для вашего приложения, которое облегчает ответ на вопрос.

...