2012-05-24 41 views
5

Diciamo che abbiamo: int A [5] [2] [3]; Ora, se lo faccio: A [1] [0] [0] = 4; significa:Puntatori, array multidimensionali e indirizzi

1.) A [1] e A [1] [0] sono puntatori?

2.) Se A [1] è un puntatore, memorizzerà l'indirizzo del puntatore A [1] [0]?

3.) Se A [1] [0] è un puntatore, quindi memorizzerà l'indirizzo di A [1] [0] [0] che NON è un puntatore ma solo una variabile che memorizza il valore di 4?

Se i punti di cui sopra sono corrette, allora perché dos il seguente codice ci danno lo stesso indirizzo intero:

int main(void) 
{ 
     int A [5] [2] [3]; 
    A[1][0][0]=4; 

    printf("%d\n\n", A[1]); 
    printf("%d\n\n", A[1][0]); 
    printf("%d\n\n",&A[1][0][0]); 

     system("pause"); 
} 

Ecco, io parto dal presupposto che A [1] è un puntatore che punta ad un altro puntatore A [1] [0] e quindi memorizza l'indirizzo del puntatore A [1] [0]. E, A [1] [0] è un puntatore che punta a VARIABLE A [1] [0] [0] e quindi memorizza l'indirizzo di VARIABLE A [1] [0] [0].

Per favore aiutatemi!

+0

Non direttamente correlato alla domanda, ma 'printf()' formato "% d" si aspetta un 'int' e se non ne fornisci uno colpisci Comportamento indefinito, che è Cattivo. Dagli "A [1]" un decodificatore array-of-2x3-int a pointer-to-int, 'A [1] [0]' un decadimento array-of-3-int a pointer-to-int, e '& A [1] [0] [0]' un puntatore-a-int. Se sizeof (int) sizeof (int *) probabilmente vedrai la spazzatura; ma un compilatore opportunamente machiavellico potrebbe emettere il codice per cancellare il tuo hard disk e comunque conformarsi allo standard. – mlp

risposta

4

Per rispondere correttamente alla tua domanda, leggere su ordine row-major, che è come gli array multidimensionale sono memorizzati in C. La Wikipedia article è un po 'troppo stringato, ma uno di questi potrebbe essere più chiaro:

http://webster.cs.ucr.edu/AoA/Windows/HTML/Arraysa2.html http://archive.gamedev.net/archive/reference/articles/article1697.html http://www.ibiblio.org/pub/languages/fortran/append-c.html

C'è anche this SO question.


In risposta diretta alla sua punti, partendo dal presupposto che si sa come funziona stoccaggio row-major:

int A[5][2][3] dichiara una regione contigua di memoria che è lunga 5 * 2 * 3 int: cinque matrici di due matrici di tre interi ciascuna. Gli array sono memorizzati uno accanto all'altro nella memoria lineare, cosicché

&A[0][0][0] == A 
&A[0][0][1] == A+1 
&A[0][1][0] == A+(1*3) 
&A[3][1][2] == A+(3*(2*3))+(1*3)+2 

A[1] non è tecnicamente un puntatore ma un array. È un array int [2][3]. Ma trovo molto meno chiaro pensare che considerare A[5][2][3] è una regione piatta della memoria, lunga trenta.

A[0][0][0] is the first integer in that region. 
A[0][0][1] is the second integer. 
A[0][0][2] is the third integer. 
A[0][1][0] is the fourth integer in this flat region. 
A[0][1][1] is the fifth integer. 
And so on until A[1][0][0] is the eleventh integer. 

Pertanto l'indirizzo del A[1][0][0] è dieci interi passati A[0][0][0]; ie, &A[1][0][0] - &A[0][0][0] == 10. Poiché il linguaggio C è molto lento sulla differenza tra array e puntatori, A[1] viene interpretato come se fosse un indirizzo quando lo si utilizza in un'espressione, anche se in realtà significa "il primo elemento in una matrice di cinque array di due array di tre numeri interi "che è a sua volta" una matrice di due matrici di tre numeri interi. "

Il risultato è che A[1] non negozio un puntatore, si è un puntatore. Ogni indirizzo di memoria da &A[0][0][0] a &A[5][2][3]-1 memorizza un numero intero nel proprio array multidimensionale.

Quello che stai pensando nei punti (2) e (3) sono arrays of pointers to arrays, che sono qualcosa di diverso.

Questo è molto più facile da spiegare con le immagini, motivo per cui dovresti trovare un vero libro di testo o un articolo sugli array C.

In generale, quando si apprendono i puntatori e gli array in C, si consiglia di dimenticare temporaneamente la lingua stessa e di fingere di essere Dennis Ritchie che inventa C su un PDP-11 con 56kb di RAM piatta. Prendi un grande foglio di carta millimetrata, numera le sue celle consecutivamente, fai finta che rappresenti la tua RAM e ogni cella sia un byte e you can work through your pointer math with pencil and paper.

C è stato inventato in quell'ambiente e la comprensione delle sue origini renderà il langauge moderno molto più sensato.

Come nota a margine, quando ho provato a scrivere questa risposta, il linguaggio di markup dello Stack Overflow ha cambiato più volte e ha rovinato gli indici nei miei esempi di array sopra. Quindi se vedi dei numeri che sembrano fuori portata per i loro array, è un errore introdotto dall'editor.

+0

È il seguente corretto: & A [0] [0] [0] == A & A [0] [0] [0] == A + 1 –

+0

& A [0] [0] [0] == A e ... – Crashworks

+0

& A [0] [0] [1] == A + 1 – Crashworks

0

leggere su Row Major Order

Sì, che non ha aiutato a tutti, stavo pensando C era maggiore colonna per un secondo non ci credo. (dimenticando cosa significavano tutte le cose)

1

Gli array multidimensionali in c non utilizzano i puntatori. Sebbene un accesso da puntatore a puntatore a puntatore possa sembrare simile, i dati effettivi potrebbero non essere contigui e c'è un sovraccarico per archiviare tutti gli indirizzi. Accesso di array multidimensionali in C è una forma di zucchero sintattico:

char a[5][7][9] 
a[d][h][w] <<==>> ((char*)a)[((9*7*d)+(9*h)+w] 

C matrici condividono la proprietà che decadono (o automaticamente trasformarsi in puntatori al primo elemento nella matrice). Di conseguenza,

a[1] (char[7][9]) --decay--> ((*char)[5][9]) pointer to char array 
&a[1] ((*char)[5][9]) no decay 

I due sono equivalenti, perché nella "degrado" più avanti in modo esplicito il puntatore, mentre avviene automaticamente nel primo.

+0

Ma come possiamo avere lo stesso risultato per questo: int main (void) { \t int A [5] [2] [3]; \t A [1] [0] [0] = 4; \t printf ("% d \ n \ n", A [1]); \t printf ("% d \ n \ n", &A[1]); \t sistema ("pausa"); } –

+0

non potevo formattarlo Ma la domanda è: A [1] e & A [1] dare la stessa uscita. ? –

+0

@JohnNash lo faranno, ho modificato la mia risposta per spiegare – Dave

1

Le ipotesi sono vere se si dispone di matrici dinamiche (ad esempio allocate con malloc/calloc).

Gli array statici, tuttavia, vengono allocati come blocchi contigui di memoria e sono semplicemente puntatori al primo elemento. Quando scrivi A[X][Y][Z] è sostanzialmente equivalente a *(A + X*YSIZE*ZSIZE + Y*SIZE + Z), non a *(*(*(A+X) + Y) + Z). Ciò consente un accesso un po 'più veloce ai dati (non è necessario accedere ai puntatori intermedi), ma richiede che tutti i dati siano allocati in un blocco e abbiano dimensioni normali.

Here è più informazione riguardante la non intercambiabilità delle matrici dinamiche statiche rispetto a C.

1

La variabile A è 5 * 2 * 3 interi, assegnato insieme come un blocco. (I.e, 30 ints).

Non ci sono puntatori coinvolti nella dichiarazione `int A [5] [2] [3]; ' - l'unico spazio riservato è quello di contenere i 30 valori int.

Quando si scrive un'espressione utilizzando A e pedici, poiché si è detto che ci sono 3 dimensioni, è necessario fornire tutte e 3 per specificare quale valore int si sta accedendo o modificando. Se usi meno di 3 pedici, specifichi solo parzialmente a cosa stai accedendo; la convenzione è che tale riferimento è considerato come una richiesta per l'indirizzo della parte rilevante dello spazio complessivo.

+0

Ma perché A [1] e A [1] ci danno lo stesso risultato: dà lo stesso indirizzo intero. –

+0

@John Nash: 'A [1]' è un array 2x3 di 'int', e in un contesto-puntatore decade all'indirizzo di quell'array. '& A [1]' è "l'indirizzo di 'A [1]'". – mlp

+0

È solo una convenzione adottata dai creatori del linguaggio C. Sembrava loro l'interpretazione più ragionevole dell'espressione e ragionevolmente "naturale". –

0

Potrebbe essere un po 'strano, ma ecco la mia spiegazione. Immagina di avere sei persone distinte numerate da 1 a 6, e sono allineate di conseguenza da 1 a 6. Se hai detto che questa squadra (le sei persone) è divisa in due gruppi, dove i primi tre (1-3) sono nel gruppo a, e il resto (4-6) sono nel gruppo B.

[1 2 3] [4 5 6]

Quindi, se vi dico che è il primo nella squadra? Diresti il ​​primo! Ma se ti chiedo chi è il primo membro del GRUPPO A del TEAM? È lo stesso, la prima persona!

Inoltre, se vi dico chi è il quarto membro della squadra? Diresti il ​​quarto! Quindi, cosa succede se ti chiedo chi è il primo membro del GRUPPO B del TEAM? È lo stesso, il quarto.


La stessa storia ti capita; A [1] è un puntatore a a partire dal del grande array (The Team), dove A [1] [0] indica di puntare allo all'inizio del primo array interno (IL PRIMO GRUPPO) all'interno il grande array (A [1]), che è identico! Quindi dici, & A [1] [0] [0], che è come andare a chiedere al primo membro del primo array interno che risiede nel grande array, qual è il tuo numero? Quindi, ripeterà lo stesso.

Nei differisce è il tipo dei puntatori e loro interpretazione, ma i loro valori sono identici . Questo perché gli array memorizzano gli elementi in modo contiguo.

Problemi correlati