Структурный указатель в структуре - PullRequest
1 голос
/ 21 апреля 2020

У меня проблемы с пониманием структурных указателей в структуре. Не могли бы вы попытаться объяснить это мне или порекомендовать какое-нибудь интересное чтение, объясняющее концепцию? Я не знаю, если это слишком общий вопрос, в таком случае извините.

Пример:

struct person{
    struct person* mother;
    struct person* father;
    int birthday;
};

struct person john;
struct person alice;
struct person rachael;
john.birthday = 1988;
alice.mother = &rachael;
alice.mother->birthday = 1970;

Ответы [ 2 ]

2 голосов
/ 21 апреля 2020

, поэтому у вас есть структура, в которой есть ссылки на указатели на структуру такого же типа, это допустимо в C, тогда как включение всей структуры (и памяти для элементов) не сработает, потому что она рекурсивная .. .

struct person{
int age; // sizeof(int) bytes
person mom; // sizeof(int) + sizeof person, which is sizeof int bytes + sizeof person...
};

, что не сработает, потому что для хранения потребуется бесконечная память.

, поэтому вам нужно хранить указатель на экземпляр, который является переменной, хранящей адрес экземпляра, или NULL (в программе с хорошим поведением это, вероятно, не должно быть другого значения)

struct person{
int age; // sizeof(int) bytes
person * mom; // sizeof (*person)...
};

, так что теперь мы можем начать делать

person QueenMother; // these have storage, but are garbage data
person QueenElizabethII;

оба эти находятся в стеке, вся используемая ими память используется там же. как вы указали, вы можете сделать назначение:

QueenElizabethII.mom = &QueenMother;

, поэтому указатель на маму - это адрес QueenMother ... который работает, теперь, если вы хотите установить возраст QueenMother через экземпляр QueenElizabethII, вы можете .

(*QueenElizabethII.mom).age = 102; // dereference and dot accessor.
//which you could also write as
QueenElizabethII.mom->age = 102;  // pointer to member accessor 

Теперь, если мы хотим переписать все это динамически, мы можем сделать что-то вроде:

struct person{
int age; // sizeof(int) bytes
person * mom; // sizeof(int) + sizeof (*person)...
};

person * QueenMother; // these dont have storage yet; 
person * QueenElizabethII;

QueenElizabethII = malloc(sizeof(person)); // now we have storage, but the data is garbage... we can initialize it to 0 with memset, or bzero; or you can do this:
QueenMother = calloc(1,sizeof(person)); // calloc is like malloc, but it zero's the data in the return

QueenElizabethII->mother = QueenMother; // now this syntax is smoother
QueenElizabethII->age = 94;
QueenElizabethII->mother->age=102; // if you are so inclined.

одна вещь, которую вы всегда должны знать с этой стратегией, это то, что вам нужно проверить, что указатели действительно указывают куда-то, или вы взломаете sh ...

if(QueenElizabethII->mother){
    QueenElizabethII->mother->age=102; // now that is safe... probably
}

, и я должен добавить, что когда вы закончите с памятью, вы должны освободить ее:

free(QueenElizabethII);
free(QueenMother);

В противном случае у вас есть утечка

2 голосов
/ 21 апреля 2020

Из вашего комментария эта часть:

alice.mother->birthday = 1970;

Эквивалентна этому:

(*(alice.mother)).birthday = 1970;

alice.mother имеет тип struct person*

(*(alice.mother)) разыменовывает указатель, поэтому тип struct person

(*(alice.mother)).birthday дает вам доступ к полю дня рождения struct person, поэтому теперь вы можете присвоить ему значение.


C просто предоставляет синтаксис c сахара в форме ->, чтобы вам не приходилось писать альтернативу, которая является безобразным беспорядком

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...