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 ie il valore 5. Questo è memorizzato. Come tutto ciò che è memorizzato, ha bisogno di un indirizzo, altrimenti non saremmo in grado di trovarlo. Diciamo che ifinisce all'indirizzo 0x12345678 e il suo amico jcon 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 into 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 ippvariabile 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, *ippotterremo l'indirizzo della variabile puntatore ip1. Scrivendo *ipp=ip2copiamo 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)
ippquando lo definisci, quindi la tua domanda è completa ;-)