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 ptrwskazuje na adres ( ! ) Zmiennej struktury, audiale 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, .kgktó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.kgjako 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).kgi 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->kgjest 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 ptrjest to „adres audi”, tj. &audiFakt, że operatory „referencyjny” & i „dereferencyjny” wzajemnie się * znoszą.