Le altre risposte sono corrette, ma nessuna di esse enfatizza l'idea che sia possibile per tutti e tre contenere lo stesso valore , e quindi sono in qualche modo incomplete.
Il motivo per cui ciò non può essere compreso dalle altre risposte è che tutte le illustrazioni, sebbene utili e decisamente ragionevoli nella maggior parte dei casi, non riescono a coprire la situazione in cui il puntatore xpunta a se stesso.
È abbastanza facile da costruire, ma chiaramente un po 'più difficile da capire. Nel programma seguente vedremo come possiamo forzare tutti e tre i valori a essere identici.
NOTA: il comportamento in questo programma non è definito, ma lo sto pubblicando qui puramente come una dimostrazione interessante di qualcosa che i puntatori possono fare, ma non dovrebbero .
#include <stdio.h>
int main () {
int *(*x)[5];
x = (int *(*)[5]) &x;
printf("%p\n", x[0]);
printf("%p\n", x[0][0]);
printf("%p\n", x[0][0][0]);
}
Questo viene compilato senza avvisi in C89 e C99 e l'output è il seguente:
$ ./ptrs
0xbfd9198c
0xbfd9198c
0xbfd9198c
È interessante notare che tutti e tre i valori sono identici. Ma questa non dovrebbe essere una sorpresa! Innanzitutto, suddividiamo il programma.
Dichiariamo xcome puntatore a una matrice di 5 elementi in cui ogni elemento è di tipo puntatore a int. Questa dichiarazione alloca 4 byte sullo stack di runtime (o più a seconda dell'implementazione; sui miei puntatori della macchina sono 4 byte), quindi xsi riferisce a una posizione di memoria effettiva. Nella famiglia di linguaggi C, i contenuti di xsono solo spazzatura, qualcosa lasciato in sospeso dal precedente utilizzo della posizione, quindi di per xsé non punta da nessuna parte, certamente non allo spazio assegnato.
Quindi, naturalmente, possiamo prendere l'indirizzo della variabile xe metterlo da qualche parte, quindi è esattamente quello che facciamo. Ma andremo avanti e lo inseriremo in x stesso. Dal momento che &xha un tipo diverso da x, dobbiamo fare un cast in modo da non ricevere avvisi.
Il modello di memoria sarebbe simile a questo:
0xbfd9198c
+------------+
| 0xbfd9198c |
+------------+
Pertanto, il blocco di memoria a 4 byte all'indirizzo 0xbfd9198ccontiene il modello di bit corrispondente al valore esadecimale 0xbfd9198c. Abbastanza semplice.
Successivamente, stampiamo i tre valori. Le altre risposte spiegano a cosa si riferisce ogni espressione, quindi la relazione dovrebbe essere chiara ora.
Possiamo vedere che i valori sono gli stessi, ma solo in un senso di livello molto basso ... i loro schemi di bit sono identici, ma i dati di tipo associati a ciascuna espressione indicano che i loro valori interpretati sono diversi. Ad esempio, se stampassimo x[0][0][0]usando la stringa di formato %d, otterremmo un numero negativo enorme, quindi i "valori" sono, in pratica, diversi, ma il modello di bit è lo stesso.
Questo in realtà è davvero semplice ... nei diagrammi, le frecce indicano semplicemente lo stesso indirizzo di memoria anziché quelli diversi. Tuttavia, mentre siamo stati in grado di forzare un risultato atteso da un comportamento indefinito, è proprio questo - indefinito. Questo non è un codice di produzione ma semplicemente una dimostrazione per completezza.
In una situazione ragionevole, si utilizzerà mallocper creare l'array di 5 puntatori int e, di nuovo, per creare gli ints che sono indicati in quell'array. mallocrestituisce sempre un indirizzo univoco (a meno che tu non abbia esaurito la memoria, nel qual caso restituisce NULL o 0), quindi non dovrai mai preoccuparti di puntatori autoreferenziali come questo.
Spero che sia la risposta completa che stai cercando. Non dovresti aspettarti x[0], x[0][0]ed x[0][0][0]essere uguale, ma potrebbero essere se forzati. Se qualcosa ti è passato per la testa, fammi sapere così posso chiarire!
x[0],x[0][0]Ex[0][0][0]hanno diversi tipi. Non possono essere confrontati. Cosa intendi con!=?