Czytam książkę zatytułowaną „Naucz się C w 21 dni” (już nauczyłem się Java i C #, więc poruszam się w znacznie szybszym tempie). Czytałem rozdział na temat wskaźników i operator->
(strzałka) pojawił się bez wyjaśnienia. Myślę, że służy do wywoływania członków i funkcji (jak odpowiednik operatora (kropka), ale dla wskaźników zamiast członków). Ale nie jestem do końca pewien..
Czy mogę prosić o wyjaśnienie i próbkę kodu?
Odpowiedzi:
foo->bar
jest równoważne(*foo).bar
, tzn. pobiera członka wywołanegobar
ze struktury, którafoo
wskazuje.źródło
->
operator nie byłby wcale potrzebny, ponieważ byłby to odpowiednik znacznie bardziej czytelnyfoo*.bar
. Można by uniknąć całego bałaganu funkcji pisania na maszynie ze wszystkimi dodatkowymi nawiasami.foo*.bar
i(*foo).bar
oba byłyby równoważnefoo->bar
? CoFoo myFoo = *foo; myFoo.bar
?Tak, to jest to.
Jest to wersja kropkowa, gdy chcesz uzyskać dostęp do elementów struktury / klasy, która jest wskaźnikiem zamiast odniesienia.
Otóż to!
źródło
pvar = &var
?a->b
jest po prostu skrótem(*a).b
pod każdym względem (to samo dla funkcji:a->b()
jest skrótem od(*a).b()
).źródło
Dodałbym do odpowiedzi „dlaczego?”.
.
jest standardowym operatorem dostępu do elementu, który ma wyższy priorytet niż*
operator wskaźnika.Kiedy próbujesz uzyskać dostęp do wewnętrznych struktur i napisałeś to,
*foo.bar
wtedy kompilator pomyślałby, że chce mieć element „bar” z „foo” (który jest adresem w pamięci) i oczywiście ten adres nie ma żadnych elementów.Dlatego musisz poprosić kompilator, aby najpierw wyrenderował opcję whith,
(*foo)
a następnie uzyskał dostęp do elementu członkowskiego:(*foo).bar
co jest nieco niezdarne do pisania, więc dobrzy ludzie wymyślili skróconą wersję:foo->bar
która jest rodzajem dostępu do członka przez operatora wskaźnika.źródło
foo->bar
jest tylko skrótem(*foo).bar
. To wszystko.źródło
Tutaj aby uzyskać dostęp do wartości
i
ij
możemy użyć zmienneja
i wskaźnikp
w następujący sposób:a.i
,(*p).i
ip->i
wszystkie są takie same.Oto
.
„Selektor bezpośredni” i->
„Selektor pośredni”.źródło
Cóż, muszę też coś dodać. Struktura jest nieco inna niż tablica, ponieważ tablica jest wskaźnikiem, a struktura nie. Więc uważaj!
Powiedzmy, że piszę ten bezużyteczny fragment kodu:
Tutaj wskaźnik
ptr
wskazuje na adres ( ! ) Zmiennej struktury,audi
ale oprócz struktury adresu ma również fragment danych ( ! )! Pierwszy element fragmentu danych ma ten sam adres, co sama struktura, i możesz uzyskać dane, usuwając tylko taki wskaźnik*ptr
(bez nawiasów klamrowych) .Ale jeśli chcesz uzyskać dostęp, innego członka niż pierwszy, trzeba dodać oznacznik jak
.km
,.kph
,.kg
które nie są niczym więcej niż offsetu do adresu bazowego w porcji danych ...Ale ze względu na preceedence nie można zapisać
*ptr.kg
jako operator dostępu.
jest oceniany przed operatorem dereference*
i można dostać*(ptr.kg)
, co nie jest możliwe, gdyż wskaźnik nie ma z nami! Kompilator wie o tym i dlatego spowoduje błąd, np .:Zamiast tego używasz tego
(*ptr).kg
i zmuszasz kompilator do 1. dereferencji wskaźnika i umożliwienia dostępu do części danych i 2. dodajesz przesunięcie (desygnator), aby wybrać element członkowski.Sprawdź to zdjęcie, które wykonałem:
Ale jeśli zagnieździlibyśmy członków, ta składnia stałaby się nieczytelna i dlatego
->
została wprowadzona. Myślę, że czytelność jest jedynym uzasadnionym powodem korzystania z niej, ponieważptr->kg
jest to o wiele łatwiejsze do napisania niż(*ptr).kg
.Teraz napiszmy to inaczej, aby lepiej widzieć połączenie.
(*ptr).kg
⟹(*&audi).kg
⟹audi.kg
. Tutaj najpierw wykorzystałem fakt, żeptr
jest to „adresaudi
”, tj.&audi
Fakt, że operatory „referencyjny”&
i „dereferencyjny” wzajemnie się*
znoszą.źródło
Musiałem wprowadzić niewielką zmianę w programie Jacka, aby go uruchomić. Po zadeklarowaniu wskaźnika struct pvar, wskaż go na adres var. Znalazłem to rozwiązanie na stronie 242 programowania Stephena Kochana w C.
Uruchom to w vimie za pomocą następującego polecenia:
Wyjdzie:
źródło
%
do przedstawienia bieżącej nazwy pliku. Tak jak:!gcc % && ./a.out
źródło
->
Operatora sprawia, że kod jest bardziej czytelny niż*
operator w niektórych sytuacjach.Takich jak: (cytowany z projektu EDK II )
Struktura
_EFI_BLOCK_IO_PROTOCOL
zawiera 4 elementy wskaźnika funkcji.Załóżmy, że masz zmienną
struct _EFI_BLOCK_IO_PROTOCOL * pStruct
i chcesz użyć starego dobrego*
operatora, aby wywołać jego wskaźnik funkcji członka. Otrzymasz kod taki jak ten:(*pStruct).ReadBlocks(...arguments...)
Ale z
->
operatorem możesz napisać w ten sposób:pStruct->ReadBlocks(...arguments...)
.Który wygląda lepiej?
źródło
wyjście wynosi 5 5 5
źródło
Kropka jest operatorem dereferencyjnym i służy do łączenia zmiennej struktury dla określonego zapisu struktury. Np .:
W ten sposób możemy użyć operatora kropki, aby uzyskać dostęp do zmiennej struktury
źródło
->
. Odpowiedzi na to pytanie udzielono już od 4,5 roku.