Nie pisałem C od bardzo dawna, więc nie jestem pewien, jak mam robić tego rodzaju rekurencyjne rzeczy ... Chciałbym, aby każda komórka zawierała inną komórkę, ale pojawia się błąd w wiersze „pola„ dziecko ”mają niepełny typ”. Co tam?
typedef struct Cell {
int isParent;
Cell child;
} Cell;
Odpowiedzi:
Oczywiście komórka nie może zawierać innej komórki, ponieważ staje się ona niekończącą się rekursją.
Jednak komórka MOŻE zawierać wskaźnik do innej komórki.
źródło
Cell
nie jest jeszcze objęty zakresem.Cell*
docell->child
.struct
s w C w zasadzie po prostu przechowują wszystkie swoje wartości obok siebie, niemożliwe byłoby przechowywanie struktury samej w sobie (ponieważ ta struktura musiałaby zawierać inną itd., Prowadząc do struktury pamięci o nieskończonym rozmiarze) .struct Cell
zapoznać się z wyjaśnieniem zastosowania , zobacz tę odpowiedź .W C nie możesz odwoływać się do typedef, które tworzysz, używając samej struktury. Musisz użyć nazwy struktury, jak w następującym programie testowym:
Chociaż jest to prawdopodobnie o wiele bardziej skomplikowane niż to w standardzie, możesz myśleć o tym jako o kompilatorze, który wie o
struct Cell
tym w pierwszej linii,typedef
ale nie wietCell
aż do ostatniej :-) Tak zapamiętałem tę regułę.źródło
Z teoretycznego punktu widzenia języki mogą wspierać jedynie struktury odwołujące się do samych siebie, a nie struktury inkluzywne.
źródło
Jest na to sposób:
Jeśli zadeklarujesz to w ten sposób, poprawnie powie kompilatorowi, że struct Cell i plain-ol'-cell są takie same. Możesz więc używać Cell tak jak zwykle. Nadal jednak trzeba używać struct Cell wewnątrz samej deklaracji początkowej.
źródło
struct Cell;
ponownie?struct Cell
.struct Cell;
zbędny. Jeśli jednak z jakiegoś powodu umieścisz ostatnie dwie linie w pliku nagłówkowym, który umieścisz przed zdefiniowaniemCell
struktury z pierwszymi czterema liniami, to dodatkowestruct Cell;
są potrzebne.typedef struct Cell Cell;
i utworzyCell
alias dlastruct Cell
. Nie ma znaczenia, czy kompilator widział jużstruct Cell { .... }
wcześniej.Wiem, że ten post jest stary, jednak aby uzyskać efekt, którego szukasz, możesz spróbować następujących rzeczy:
W każdym z dwóch przypadków wymienionych w powyższym fragmencie kodu MUSISZ zadeklarować swoją podrzędną strukturę Cell jako wskaźnik. Jeśli tego nie zrobisz, otrzymasz błąd „pole 'dziecko' ma niepełny typ”. Powodem jest to, że "struct Cell" musi być zdefiniowane, aby kompilator wiedział, ile miejsca przydzielić, gdy jest używany.
Jeśli spróbujesz użyć słowa „struct Cell” w definicji „struct Cell”, kompilator nie może jeszcze wiedzieć, ile miejsca ma zajmować „struct Cell”. Jednak kompilator już wie, ile miejsca zajmuje wskaźnik i (z deklaracją forward) wie, że "Cell" jest rodzajem "struct Cell" (chociaż nie wie jeszcze jak duża jest "struct Cell" ). Zatem kompilator może zdefiniować „Cell *” w definiowanej strukturze.
źródło
Przejdźmy przez podstawową definicję typedef. typedef służy do definiowania aliasu do istniejącego typu danych, który jest zdefiniowany przez użytkownika lub wbudowany.
na przykład
Zamieszanie występuje tutaj ze strukturą odwołującą się do samego siebie, z powodu elementu członkowskiego tego samego typu danych, który nie został wcześniej zdefiniowany. Więc w standardowy sposób możesz napisać swój kod jako: -
Ale ostatnia opcja zwiększa dodatkowe linie i słowa, których zwykle nie chcemy robić (jesteśmy tacy leniwi, wiesz;)). Więc wolę Widok 2.
źródło
typedef
składni jest nieprawidłowe (rozważ nptypedef int (*foo)(void);
.). Twoje przykłady View 1 i View 2 nie działają: tworząstruct Cell
niekompletny typ, więc nie możesz faktycznie użyćchild
w swoim kodzie.Inną wygodną metodą jest wstępne zdefiniowanie struktury za pomocą tagu struktury jako:
źródło
Struktura, która zawiera odniesienie do siebie. Jest to częste zjawisko w strukturze opisującej węzeł dla listy połączeń. Każdy węzeł potrzebuje odniesienia do następnego węzła w łańcuchu.
źródło
Wszystkie poprzednie odpowiedzi są świetne. Pomyślałem tylko, że chcę wyjaśnić, dlaczego struktura nie może zawierać instancji własnego typu (nie odniesienia).
bardzo ważne jest, aby pamiętać, że struktury są typami wartości, tj. zawierają rzeczywistą wartość, więc kiedy deklarujesz strukturę, kompilator musi zdecydować, ile pamięci przeznaczyć na jej instancję, więc przechodzi przez wszystkie jej elementy i dodaje w celu obliczenia całej pamięci struktury, ale jeśli kompilator znalazł wewnątrz instancję tej samej struktury, to jest to paradoks (tj. aby wiedzieć, ile pamięci zajmuje struktura A, musisz zdecydować, ile pamięci struct A trwa!).
Ale typy odwołań są różne, jeśli struktura „A” zawiera „odwołanie” do instancji własnego typu, chociaż nie wiemy jeszcze, ile pamięci jest do niej przydzielone, wiemy, ile pamięci jest przydzielone do pamięci adres (tj. odniesienie).
HTH
źródło