Perché x [0]! = X [0] [0]! = X [0] [0] [0]?


149

Sto studiando un po 'di C ++ e sto combattendo con i puntatori. Capisco che posso avere 3 livelli di puntatori dichiarando:

int *(*x)[5];

in modo che *xsia un puntatore a un array di 5 elementi che sono puntatori a int. Anche io lo so x[0] = *(x+0);, x[1] = *(x+1)e così via ....

Quindi, data la dichiarazione di cui sopra, perché x[0] != x[0][0] != x[0][0][0]?


58
x[0], x[0][0]E x[0][0][0]hanno diversi tipi. Non possono essere confrontati. Cosa intendi con !=?
Bolov,

4
@celticminstrel non sono gli stessi: int **x[5]è un array di 5 elementi. Un elemento è un puntatore al puntatore a int`
bolov

5
@celticminstrel int** x[5]sarebbe una matrice di cinque puntatori che puntano a puntatori che puntano a int. int *(*x)[5]è un puntatore a un array di cinque puntatori che puntano a int.
emlai,


5
@ Leo91: in primo luogo, hai due livelli di puntatori qui, non tre. In secondo luogo, cosa x[0] != x[0][0] != x[0][0][0]significa? Questo non è un confronto valido in C ++. Anche se lo dividi in x[0] != x[0][0]e x[0][0] != x[0][0][0]non è ancora valido. Quindi, cosa significa la tua domanda?
AnT

Risposte:


261

xè un puntatore a un array di 5 puntatori a int.
x[0]è un array di 5 puntatori a int.
x[0][0]è un puntatore a un int.
x[0][0][0]è un int.

                       x[0]
   Pointer to array  +------+                                 x[0][0][0]         
x -----------------> |      |         Pointer to int           +-------+
               0x500 | 0x100| x[0][0]---------------->   0x100 |  10   |
x is a pointer to    |      |                                  +-------+
an array of 5        +------+                        
pointers to int      |      |         Pointer to int                             
               0x504 | 0x222| x[0][1]---------------->   0x222                    
                     |      |                                             
                     +------+                                             
                     |      |         Pointer to int                              
               0x508 | 0x001| x[0][2]---------------->   0x001                    
                     |      |                                             
                     +------+                                             
                     |      |         Pointer to int                              
               0x50C | 0x123| x[0][3]---------------->   0x123                    
                     |      |                                             
                     +------+                                             
                     |      |         Pointer to int                              
               0x510 | 0x000| x[0][4]---------------->   0x000                    
                     |      |                                             
                     +------+                                             

Potete vederlo

  • x[0]è un array e verrà convertito in puntatore al suo primo elemento quando utilizzato in un'espressione (con alcune eccezioni). Pertanto x[0]fornirà l'indirizzo del suo primo elemento x[0][0]che è 0x500.
  • x[0][0]contiene l'indirizzo di un intche è 0x100.
  • x[0][0][0]contiene un intvalore di 10.

Quindi, x[0]è uguale a &x[0][0]e quindi, &x[0][0] != x[0][0].
Quindi, x[0] != x[0][0] != x[0][0][0].


Questo diagramma è un po 'confuso per me: 0x100dovrebbe apparire immediatamente a sinistra della scatola contenente 10, allo stesso modo che 0x500appare a sinistra della sua scatola. Invece di essere lontano a sinistra e in basso.
MM

@MattMcNabb; Non penso che dovrebbe essere fonte di confusione, ma cambia secondo il tuo suggerimento per maggiore chiarezza.
Accade il

4
@haccks - Piacere mio :) Il motivo per cui quel diagramma è fantastico è perché non hai nemmeno bisogno della spiegazione che hai dato che lo segue. Lo stesso diagramma è autoesplicativo che risponde già alla domanda. Il testo che segue è semplicemente un bonus.
Rayryeng,

1
Puoi anche usare yed, un software per diagrammi. Mi aiuta molto ad organizzare i miei pensieri
rpax

@GrijeshChauhan Uso asciiflow per i commenti del codice, yeD per le presentazioni :)
rpax,

133
x[0] != x[0][0] != x[0][0][0]

è, secondo il tuo post,

*(x+0) != *(*(x+0)+0) != *(*(*(x+0)+0)+0)`  

che è semplificato

*x != **x != ***x

Perché dovrebbe essere uguale?
Il primo è l'indirizzo di un puntatore.
Il secondo è l'indirizzo di un altro puntatore.
E il terzo ha un certo intvalore.


Non riesco a capire ... se x [0], x [0] [0], x [0] [0] [0] è equivalente a * (x + 0), * (x + 0 + 0) , * (x + 0 + 0 + 0), perché dovrebbero avere indirizzi diversi?
Leo91,

41
@ Leo91 x[0][0]è (x[0])[0], cioè *((*(x+0))+0), no *(x+0+0). La dereference avviene prima del secondo [0].
emlai,

4
@ Leo91 x[0][0] != *(x+0+0)proprio come x[2][3] != x[3][2].
özg

@ Leo91 Il secondo commento che hai "capito adesso" è stato rimosso. Non capisci qualcosa (che potrebbe essere spiegato meglio nella risposta) o non stai facendo questo? (ad alcune persone piace eliminare i commenti senza molto contenuto informativo)
deviantfan,

@deviantfan scusami non riesco a capire cosa intendi. Comprendo le risposte e molti commenti che hanno contribuito a chiarire il concetto.
Leo91,

50

Ecco il layout di memoria del puntatore:

   +------------------+
x: | address of array |
   +------------------+
            |
            V
            +-----------+-----------+-----------+-----------+-----------+
            | pointer 0 | pointer 1 | pointer 2 | pointer 3 | pointer 4 |
            +-----------+-----------+-----------+-----------+-----------+
                  |
                  V
                  +--------------+
                  | some integer |
                  +--------------+

x[0]restituisce "indirizzo dell'array",
x[0][0]restituisce "puntatore 0",
x[0][0][0]restituisce "un numero intero".

Credo, dovrebbe essere ovvio ora, perché sono tutti diversi.


Quanto sopra è abbastanza vicino per la comprensione di base, motivo per cui l'ho scritto nel modo in cui l'ho scritto. Tuttavia, come giustamente haccks sottolinea, la prima riga non è precisa al 100%. Quindi ecco tutti i dettagli:

Dalla definizione del linguaggio C, il valore di x[0]è l'intero array di puntatori interi. Tuttavia, le matrici sono qualcosa con cui non puoi davvero fare nulla in C. Manipoli sempre il loro indirizzo o i loro elementi, mai l'intero array nel suo insieme:

  1. È possibile passare x[0]alla sizeofdell'operatore. Ma questo non è davvero un uso del valore, il suo risultato dipende solo dal tipo.

  2. Puoi prendere il suo indirizzo che dà il valore di x, cioè "indirizzo dell'array" con il tipo int*(*)[5]. In altre parole:&x[0] <=> &*(x + 0) <=> (x + 0) <=> x

  3. In tutti gli altri contesti , il valore di x[0]decadrà in un puntatore al primo elemento dell'array. Cioè, un puntatore con il valore "indirizzo dell'array" e il tipo int**. L'effetto è lo stesso di se fosse stato eseguito il cast xsu un puntatore di tipo int**.

A causa del decadimento del puntatore di array nel caso 3., tutti gli usi di in x[0]definitiva comportano un puntatore che punta all'inizio dell'array di puntatori; la chiamata printf("%p", x[0])stamperà il contenuto delle celle di memoria etichettate come "indirizzo dell'array".


1
x[0]non è l'indirizzo dell'array.
Accade il

1
@haccks Sì, seguendo la lettera dello standard, x[0]non è l'indirizzo dell'array, è l'array stesso. Ho aggiunto una spiegazione approfondita di questo e del motivo per cui ho scritto che x[0]è "l'indirizzo dell'array". Spero vi piaccia.
cmaster - ripristina monica il

grafici fantastici che lo spiegano perfettamente!
MK

"Tuttavia, le matrici sono qualcosa con cui non puoi davvero fare nulla in C." -> Esempio di contatore: printf("%zu\n", sizeof x[0]);riporta la dimensione dell'array, non la dimensione di un puntatore.
chux - Ripristina Monica l'

@ chux-ReinstateMonica E sono andato a dire "Hai sempre manipolare sia il loro indirizzo o loro elementi, non l'intero array nel suo insieme", seguito da punto 1 dell'enumerazione dove parlo l'effetto di sizeof x[0]...
cmaster - ripristina monica l'

18
  • x[0]dereferenzia il puntatore più esterno ( puntatore alla matrice di dimensione 5 del puntatore a int) e risulta in una matrice della dimensione 5 del puntatore a int;
  • x[0][0]dereferenzia il puntatore più esterno e indicizza l'array, risultando in un puntatore a int;
  • x[0][0][0] dereferenzia tutto, ottenendo un valore concreto.

A proposito, se ti senti mai confuso dal significato di questo tipo di dichiarazioni, usa cdecl .


11

Consideriamo passo dopo passo le espressioni x[0], x[0][0]e x[0][0][0].

Come xdefinito nel modo seguente

int *(*x)[5];

allora expression x[0]è una matrice di tipo int *[5]. Prendi in considerazione che espressione x[0]è equivalente a espressione *x. Cioè, dereferenziando un puntatore a un array, otteniamo l'array stesso. Lasciatelo denotare come se avessimo una dichiarazione

int * y[5];

L'espressione x[0][0]è equivalente y[0]e ha tipo int *. Lasciatelo indicare come z, ovvero abbiamo una dichiarazione

int *z;

espressione x[0][0][0]è equivalente a espressione y[0][0]che a sua volta è equivalente a espressione z[0]e ha tipo int.

Quindi abbiamo

x[0] ha tipo int *[5]

x[0][0] ha tipo int *

x[0][0][0] ha tipo int

Quindi sono oggetti di diversi tipi e a proposito di dimensioni diverse.

Esegui per esempio

std::cout << sizeof( x[0] ) << std::endl;
std::cout << sizeof( x[0][0] ) << std::endl;
std::cout << sizeof( x[0][0][0] ) << std::endl;

10

Prima cosa che devo dire

x [0] = * (x + 0) = * x;

x [0] [0] = * (* (x + 0) + 0) = * * x;

x [0] [0] [0] = * (* (* (x + 0) + 0)) = * * * x;

Quindi * x ≠ * * x ≠ * * * x

Dall'immagine seguente tutto è chiaro.

  x[0][0][0]= 2000

  x[0][0]   = 1001

  x[0]      = 10

inserisci qui la descrizione dell'immagine

È solo un esempio, in cui il valore di x [0] [0] [0] = 10

e l'indirizzo di x [0] [0] [0] è 1001

quell'indirizzo è memorizzato in x [0] [0] = 1001

e l'indirizzo di x [0] [0] è 2000

e quell'indirizzo è memorizzato in x [0] = 2000

Quindi x [0] [0] [0] x [0] [0] x [0]

.

editings

Programma 1:

{
int ***x;
x=(int***)malloc(sizeof(int***));
*x=(int**)malloc(sizeof(int**));
**x=(int*)malloc(sizeof(int*));
***x=10;
printf("%d   %d   %d   %d\n",x,*x,**x,***x);
printf("%d   %d   %d   %d   %d",x[0][0][0],x[0][0],x[0],x,&x);
}

Produzione

142041096 142041112 142041128 10
10 142041128 142041112 142041096 -1076392836

Programma 2:

{
int x[1][1][1]={10};
printf("%d   %d   %d   %d \n ",x[0][0][0],x[0][0],x[0],&x);
}

Produzione

10   -1074058436   -1074058436   -1074058436 

3
La tua risposta è fuorviante. x[0]non contiene l'indirizzo di formica. È un array. Decadrà per puntare al suo primo elemento.
Accade il

Ummm ... cosa significa? La tua modifica è come una ciliegina sulla torta alla tua risposta sbagliata. Non ha senso
hack

@haccks Se utilizza solo i puntatori, questa risposta sarà corretta. Ci saranno alcuni cambiamenti nella sezione degli indirizzi quando si usa Array
apm

7

Se dovessi visualizzare le matrici da una prospettiva del mondo reale, sembrerebbe così:

x[0]è un container pieno di casse.
x[0][0]è un'unica cassa, piena di scatole da scarpe, all'interno del container.
x[0][0][0]è una singola scatola da scarpe all'interno della cassa, all'interno del container.

Anche se fosse l'unica scatola da scarpe nell'unica cassa nel container, è comunque una scatola da scarpe e non un container


1
non x[0][0]sarebbe un'unica cassa piena di pezzi di carta su cui sono scritte le posizioni delle scatole da scarpe?
wchargin,

4

C'è un principio in C ++ in modo che: una dichiarazione di una variabile indica esattamente il modo di usare la variabile. Considera la tua dichiarazione:

int *(*x)[5];

che può essere riscritto come (per maggiore chiarezza):

int *((*x)[5]);

In base al principio, abbiamo:

*((*x)[i]) is treated as an int value (i = 0..4)
 (*x)[i] is treated as an int* pointer (i = 0..4)
 *x is treated as an int** pointer
 x is treated as an int*** pointer

Perciò:

x[0] is an int** pointer
 x[0][0] = (x[0]) [0] is an int* pointer
 x[0][0][0] = (x[0][0]) [0] is an int value

Quindi puoi capire la differenza.


1
x[0]è un array di 5 pollici, non un puntatore. (può decadere in un puntatore nella maggior parte dei contesti, ma la distinzione è importante qui).
MM

Ok, ma dovresti dire: x [0] è un array di 5 puntatori int *
Nghia Bui

Per dare la derivazione corretta per @MattMcNabb: *(*x)[5]è un int, quindi (*x)[5]è un int *, quindi *xè un (int *)[5], quindi xè un *((int *)[5]). Cioè, xè un puntatore a un array di 5 puntatori a int.
wchargin,

2

Stai cercando di confrontare diversi tipi per valore

Se prendi gli indirizzi potresti ottenere più di quello che ti aspetti

Tieni presente che la tua dichiarazione fa la differenza

 int y [5][5][5];

permetterebbe i confronti che si desidera, dal momento che y, y[0], y[0][0], y[0][0][0]avrebbe valori e tipi diversi, ma lo stesso indirizzo

int **x[5];

non occupa spazio contiguo.

xe x [0]hanno lo stesso indirizzo, ma x[0][0]e x[0][0][0]sono ciascuno con indirizzi diversi


2
int *(*x)[5]è diverso daint **x[5]
MM

2

Essere pun puntatore: stai accumulando dereferenze p[0][0], che è equivalente a *((*(p+0))+0).

Nella notazione C reference (&) e dereference (*):

p == &p[0] == &(&p[0])[0] == &(&(&p[0])[0])[0])

È equivalente a:

p == &*(p+0) == &*(&*(p+0))+0 == &*(&*(&*(p+0))+0)+0

Guarda che, & * può essere refactored, semplicemente rimuovendolo:

p == p+0 == p+0+0 == p+0+0+0 == (((((p+0)+0)+0)+0)+0)

Cosa stai cercando di mostrare con tutto dopo la tua prima frase? Hai solo molte varianti p == p . &(&p[0])[0]è diverso dap[0][0]
MM

Il ragazzo ha chiesto perché 'x [0]! = X [0] [0]! = X [0] [0] [0]' quando x è un puntatore, giusto? Ho provato a mostrargli che può essere intrappolato dalla notazione C di dereference (*) quando ha impilato [0]. Quindi, è un tentativo di mostrargli la notazione corretta per avere x uguale x [0], facendo nuovamente riferimento a x [0] con &, e così via.
Luciano,

1

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!


Direi che un altro strano uso dei puntatori che abbia mai visto.
Accade l'

@haccks Sì, è abbastanza strano, ma quando lo scomponi, è altrettanto semplice come gli altri esempi. È solo un caso in cui gli schemi di bit sono tutti uguali.
Purag,

Il codice causa un comportamento indefinito. x[0]in realtà non rappresenta un oggetto valido del tipo corretto
MM

@MattMcNabb È indefinito e in realtà sono molto chiaro. Non sono d'accordo sul tipo. xè un puntatore a un array, quindi possiamo usare l' []operatore per specificare un offset da quel puntatore e dereferenziarlo. Cosa c'è di strano lì? Il risultato di x[0]è un array e C non si lamenta se lo stampi usando in %pquanto è comunque implementato sotto.
Purag,

E compilare questo con la -pedanticbandiera non produce avvertimenti, quindi C va bene con i tipi ...
Purag

0

Il tipo di int *(*x)[5]è int* (*)[5]cioè un puntatore a un array di 5 puntatori a ints.

  • xè l'indirizzo del primo array di 5 puntatori a ints (un indirizzo con tipo int* (*)[5])
  • x[0]l'indirizzo del primo array di 5 puntatori a ints (stesso indirizzo con tipo int* [5]) (indirizzo offset x per 0*sizeof(int* [5])es. indice * dimensione del tipo-essendo-puntato-a e dereference)
  • x[0][0]è il primo puntatore a un int nell'array (lo stesso indirizzo con tipo int*) (offset indirizzo x di 0*sizeof(int* [5])e dereference e quindi di 0*sizeof(int*)e dereference)
  • x[0][0][0]è il primo int a cui punta il puntatore a un int (offset offset x by 0*sizeof(int* [5])e dereference e offset quell'indirizzo by 0*sizeof(int*)e dereference e offset quell'indirizzo by 0*sizeof(int)e dereference)

Il tipo di int *(*y)[5][5][5]è int* (*)[5][5][5]cioè un puntatore a un array 3d di puntatori 5x5x5 a ints

  • x è l'indirizzo del primo array 3d di puntatori 5x5x5 a ints con type int*(*)[5][5][5]
  • x[0]è l'indirizzo del primo array 3d di puntatori 5x5x5 a ints (indirizzo offset x by 0*sizeof(int* [5][5][5])e dereference)
  • x[0][0]è l'indirizzo del primo array 2d di puntatori 5x5 a ints (offset dell'indirizzo x di 0*sizeof(int* [5][5][5])e dereference quindi offset dell'indirizzo di 0*sizeof(int* [5][5]))
  • x[0][0][0]è l'indirizzo del primo array di 5 puntatori a ints (offset indirizzo x di 0*sizeof(int* [5][5][5])e dereference e offset quell'indirizzo di 0*sizeof(int* [5][5])e offset quell'indirizzo di 0*sizeof(int* [5]))
  • x[0][0][0][0]è il primo puntatore a un int nella matrice (offset indirizzo x di 0*sizeof(int* [5][5][5])e dereference e offset quell'indirizzo di 0*sizeof(int* [5][5])e offset quell'indirizzo di 0*sizeof(int* [5])e offset quell'indirizzo di 0*sizeof(int*)e dereference)
  • x[0][0][0][0][0]è il primo int a cui punta il puntatore a un int (offset offset x by 0*sizeof(int* [5][5][5])e dereference e offset quell'indirizzo by 0*sizeof(int* [5][5])e offset quell'indirizzo by 0*sizeof(int* [5])e offset quell'indirizzo by 0*sizeof(int*)e dereference e offset quell'indirizzo by 0*sizeof(int)e dereference)

Per quanto riguarda il decadimento dell'array:

void function (int* x[5][5][5]){
  printf("%p",&x[0][0][0][0]); //get the address of the first int pointed to by the 3d array
}

Ciò equivale a passare int* x[][5][5]o, int* (*x)[5][5]cioè, tutti decadono verso quest'ultimo. Questo è il motivo per cui non riceverai un avviso del compilatore da utilizzare x[6][0][0]nella funzione, ma lo farai x[0][6][0]perché le informazioni sulla dimensione vengono conservate

void function (int* (*x)[5][5][5]){
  printf("%p",&x[0][0][0][0][0]); //get the address of the first int pointed to by the 3d array
}
  • x[0] è l'indirizzo del primo array 3d di puntatori 5x5x5 a ints
  • x[0][0] è l'indirizzo del primo array 2d di puntatori 5x5 a ints
  • x[0][0][0] è l'indirizzo del primo array di 5 puntatori a ints
  • x[0][0][0][0] è il primo puntatore a un int nella matrice
  • x[0][0][0][0][0] è il primo int a cui punta il puntatore a un int

Nell'ultimo esempio, è semanticamente molto più chiaro da usare *(*x)[0][0][0]piuttosto che da x[0][0][0][0][0]questo, perché il primo e l'ultimo [0]qui sono interpretati come una dereferenza del puntatore piuttosto che un indice in un array multidimensionale, a causa del tipo. Sono comunque identici perché (*x) == x[0]indipendentemente dalla semantica. Potresti anche usare *****x, che sembrerebbe dereferenziare il puntatore 5 volte, ma in realtà è interpretato esattamente lo stesso: un offset, una dereference, una dereference, 2 offset in un array e una dereference, semplicemente a causa del tipo stai applicando l'operazione a.

Essenzialmente quando [0]o *una *di tipo non matrice, è un offset e un dereference causa del ordine di precedenza *(a + 0).

Quando si [0]o *un *per un tipo di matrice allora è un offset poi un dereference idempotente (la dereferenziazione viene risolto mediante il compilatore per produrre lo stesso indirizzo - è un'operazione idempotente).

Quando tu [0]o *un tipo con un tipo di array 1d, allora è un offset, quindi una dereferenza

Se tu [0]o **un tipo di array 2d, allora è solo un offset, cioè un offset e quindi una dereference idempotente.

Se tu [0][0][0]o ***un tipo di array 3d è un offset + dereference idempotente, allora un offset + dereference idempotente quindi un offset + dereference idempotente quindi una dereference. La vera dereferenza si verifica solo quando il tipo di array è completamente rimosso.

Per l'esempio del int* (*x)[1][2][3]tipo è scartato in ordine.

  • x ha un tipo int* (*)[1][2][3]
  • *xha un tipo int* [1][2][3](offset 0 + dereference idempotente)
  • **xha un tipo int* [2][3](offset 0 + dereference idempotente)
  • ***xha un tipo int* [3](offset 0 + dereference idempotente)
  • ****xha un tipo int*(offset 0 + dereference)
  • *****xha tipo int(offset 0 + dereference)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.