La mia opinione molto personale è che le immagini con le frecce che puntano in questo modo o che rendono più difficile la comprensione dei puntatori. Li fa sembrare delle entità astratte e misteriose. Non sono.
Come tutto il resto nel tuo computer, i puntatori sono numeri . Il nome "puntatore" è solo un modo elegante di dire "una variabile contenente un indirizzo".
Pertanto, lasciatemi mescolare le cose spiegando come funziona effettivamente un computer.
Abbiamo un int
, ha il nome i
e il valore 5. Questo è memorizzato. Come tutto ciò che è memorizzato, ha bisogno di un indirizzo, altrimenti non saremmo in grado di trovarlo. Diciamo che i
finisce all'indirizzo 0x12345678 e il suo amico j
con valore 6 finisce subito dopo. Supponendo una CPU a 32 bit in cui int è 4 byte e i puntatori sono 4 byte, quindi le variabili vengono archiviate nella memoria fisica in questo modo:
Address Data Meaning
0x12345678 00 00 00 05 // The variable i
0x1234567C 00 00 00 06 // The variable j
Ora vogliamo puntare a queste variabili. Creiamo un puntatore a int int* ip1
, e uno int* ip2
. Come ogni cosa nel computer, anche queste variabili puntatore vengono allocate da qualche parte nella memoria. Supponiamo che finiscano ai successivi indirizzi adiacenti in memoria, immediatamente dopo j
. ip1=&i;
Impostiamo i puntatori per contenere gli indirizzi delle variabili precedentemente allocate: ("copia l'indirizzo di i in ip1") e ip2=&j
. Quello che succede tra le righe è:
Address Data Meaning
0x12345680 12 34 56 78 // The variable ip1(equal to address of i)
0x12345684 12 34 56 7C // The variable ip2(equal to address of j)
Quindi quello che abbiamo ottenuto erano solo alcuni blocchi di memoria a 4 byte contenenti numeri. Non ci sono frecce mistiche o magiche da nessuna parte in vista.
In effetti, solo guardando un dump della memoria, non possiamo dire se l'indirizzo 0x12345680 contiene un int
o int*
. La differenza sta nel modo in cui il nostro programma sceglie di utilizzare i contenuti memorizzati a questo indirizzo. (Il compito del nostro programma è in realtà solo quello di dire alla CPU cosa fare con questi numeri.)
Quindi aggiungiamo ancora un altro livello di riferimento indiretto con int** ipp = &ip1;
. Ancora una volta, abbiamo solo un pezzo di memoria:
Address Data Meaning
0x12345688 12 34 56 80 // The variable ipp
Il modello sembra familiare. Ancora un altro pezzo di 4 byte contenente un numero.
Ora, se avessimo un dump della memoria della RAM fittizia sopra descritta, potremmo controllare manualmente dove puntano questi puntatori. Diamo un'occhiata a ciò che è memorizzato all'indirizzo della ipp
variabile e troviamo il contenuto 0x12345680. Qual è ovviamente l'indirizzo in cui ip1
è memorizzato. Possiamo andare a quell'indirizzo, controllare i contenuti lì, e trovare l'indirizzo di i
, e infine possiamo andare a quell'indirizzo e trovare il numero 5.
Quindi, se prendiamo il contenuto di ipp, *ipp
otterremo l'indirizzo della variabile puntatore ip1
. Scrivendo *ipp=ip2
copiamo ip2 in ip1, è equivalente a ip1=ip2
. In entrambi i casi avremmo
Address Data Meaning
0x12345680 12 34 56 7C // The variable ip1
0x12345684 12 34 56 7C // The variable ip2
(Questi esempi sono stati forniti per una CPU big endian)
ipp
quando lo definisci, quindi la tua domanda è completa ;-)