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 x
punta 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 x
come 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 x
si riferisce a una posizione di memoria effettiva. Nella famiglia di linguaggi C, i contenuti di x
sono solo spazzatura, qualcosa lasciato in sospeso dal precedente utilizzo della posizione, quindi di per x
sé non punta da nessuna parte, certamente non allo spazio assegnato.
Quindi, naturalmente, possiamo prendere l'indirizzo della variabile x
e metterlo da qualche parte, quindi è esattamente quello che facciamo. Ma andremo avanti e lo inseriremo in x stesso. Dal momento che &x
ha 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 0xbfd9198c
contiene 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à malloc
per creare l'array di 5 puntatori int e, di nuovo, per creare gli ints che sono indicati in quell'array. malloc
restituisce 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!=
?