2014-12-05 15 views
7

Quando ho dichiarare un nuovo array come questo:C++ puntatore vs notazione di matrice

int foo[5] 

è foo davvero un puntatore al primo elemento della matrice? Sarei in grado di farlo:

*(foo+2) 

per accedere al terzo elemento dell'array? Diciamo che io sto facendo una matrice 2D:

int foo[3][4] 

È foo ora un int**?

+11

* È davvero un punto il primo elemento dell'array? * - No, è un array. * È foo now a int \ * \ *? * - No, è un array 2D. Vedi [array] (http://stackoverflow.com/questions/4810664/how-do-i-use-arrays-in-c) – chris

+0

@chris, quindi se volessi iterare su di esso usando la notazione del puntatore, vorrei bisogno di fare un 'int * ptr = & foo [0]'? – n0pe

+0

@maxmackie 'int * ptr = foo' sarebbe sufficiente. –

risposta

5

n, 'foo' è un tipo di matrice in entrambi i casi, ma quando un puntatore è previsto in un'espressione con 'foo', è implicitamente convertito in uno (che indica il primo elemento dell'array). Tutti gli array hanno questo comportamento. Nel caso, dato che l'aggiunta può essere eseguita tramite i tipi di puntatore, ma non con gli array, 'foo' viene convertito in 'int *'.

*(foo+2) // 'foo' is implicitly converted into 'int *', pointing to 'foo' first element 

foo + 1 //same as above 

Ma ora si può chiedere, quali sono le proprietà del tipo di 'allineamento' e perché dovremmo mai usare, al posto del puntatore implicito a primo cast elemento. Le cose sono che non sono molto.Si può dire la dimensione di un oggetto con tipo array come questo:

sizeof(foo) //returns the size which array 'foo' occupies 

E ottenere il suo indirizzo usando il '&' operatore:

&foo // '&foo' has type of 'int (*)[5]' 

È anche possibile creare funzioni con i parametri di 'serie 'riferimento (o puntatore) digitare per accettare solo quelli con dimensioni specificate (che non è possibile se sono solo puntatori e si aspettano che gli array siano passati a decadere in tali). Esempio:

void func(int (&)[5]); 

void func1(int (*arg)[5]); // should be accessed by '*arg', allow the use of null-pointers 

void func2(int *); //same as the misleading 'void func2(int [5])' or 'void func2(int [6])' etc. 

int foo[5]; 

int foo1[6]; 

func(foo); // 'foo' type is ('int [5]') - ok 

func1(&foo); // '&foo' type is ('int (*)[5]') - ok 

func(foo1); // 'foo1' type is ('int [6]') - not allowed, param type is 'int (&)[5]' ! 

func1(&foo1); // '&foo1' type is ('int (*)[6]') - not allowed, param type is 'int (*)[5]' ! 

func2(foo); // 'foo' is implicitly converted to 'int *' - ok 

func2(foo1); // 'foo1' is implicitly converted to 'int *' - ok 

Nel secondo caso quando l'array è 2D, vengono applicate le stesse proprietà. La sua dichiarazione significa questo: 'un array di 3 elementi con tipo array di 4 elementi con tipo int' Quindi in realtà è solo un array di array e niente di più. Il suo puntatore implicito alla conversione del primo elemento non è di tipo 'int **' ma invece di 'int (*) [4]', poiché ogni elemento di esso è un altro array.

La dichiarazione può essere scritta in questo modo anche:

int (foo[3])[4]; 

Notare inoltre non possono essere assegnati 'allineamenti', in modo che non possono essere passate per valore o restituito dalle funzioni. Quello che voglio dire è:

int funcReturningArray()[2]; //not allowed 

int funcAcceptingArray(int [2]); //just converted into pointer 

int funcAcceptingArray(int *); //same as above 

Anche se i parametri di matrice sono sintatticamente accettate a causa di motivi di eredità (? O perché qualcosa d'altro), il loro vero significato non è mai tollerato e sono solo 'aggiustato' per i puntatori.

Nota: la conversione implicita del tipo di matrice in un puntatore del suo primo elemento è talvolta denominata "Array to pointer decay".

+0

Risposta generalmente corretta, ma potrebbe essere migliorata: 1. Probabilmente dovresti dire che l'array * decade * in un puntatore invece di "è implicitamente convertito in uno". Il cast di parole di solito implica che il programmatore costringa il compilatore a fare qualcosa contro la sua migliore conoscenza, non che qualcosa implicitamente e senza sforzo cambia tipo sotto il cofano. Potresti anche migliorare significativamente la leggibilità del grande blocco di codice accorciando drasticamente i commenti. Qualcosa del tipo: '// errore: type errato' o' // ok: foo decays in int * '. – cmaster

+0

'decadimento' è la parola chiave. Dovresti metterlo all'inizio – texasbruce

-4

Nessun array non è un puntatore ma nelle espressioni viene convertito in puntatore di valore ai loro primi elementi. Quindi, in questa espressione

*(foo+2) 

in un primo momento foo viene convertito in rvalue puntatore e quindi viene utilizzato l'aritmetica dei puntatori.

Per questa dichiarazione di matrice

int foo[3][4]; 

nome foo usato nelle espressioni viene convertito in rvalue puntatore di tipo int (*)[4]

La parola rvalue significa che, per esempio, non si può scrivere ++foo

Questo è il compilatore per il nome dell'array usato nelle espressioni crea un oggetto temporaneo che è un poimnter al primo elemento dell'array.

Tenere presente che se si utilizza ad esempio l'operatore sizeof con un nome di matrice, l'ultimo non verrà convertito in un puntatore. Quindi per la vostra ultima definizione del campo

sizeof(foo) 

sarà equivalente a

3 * 4 * sizeof(int) 

mentre

sizeof(int (*)[4]) 

restituirà la dimensione del puntatore stesso.

E infine se si applica l'operatore & a un nome di matrice, si otterrà un puntatore all'array stesso. Ad esempio

int foo[3][4]; 

int (*ptr_to_foo)[3][4] = &foo; 
+0

Realmente non capisco chi ha downvoted questo rispondi, è perfettamente corretto! – cmaster

+0

_ "Questo è il compilatore per il nome di matrice utilizzato nelle espressioni crea un oggetto temporaneo che è un poimnter al primo elemento dell'array." _ Errore di analisi ... –

Problemi correlati