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:
#include <stdio.h>
typedef struct{
int km;
int kph;
int kg;
} car;
int main(void){
car audi = {12000, 230, 760};
car *ptr = &audi;
}
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 .:
error: ‘ptr’ is a pointer; did you mean to use ‘->’?
printf("%d\n", *ptr.km);
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, że ptr
jest to „adres audi
”, tj. &audi
Fakt, że operatory „referencyjny” &
i „dereferencyjny” wzajemnie się *
znoszą.