2009-04-29 12 views
11

Say abbiamo il codice seguente:C indirizzo matrice confusione

int main(){ 
    int a[3]={1,2,3}; 
    printf("  E: 0x%x\n", a); 
    printf(" &E[2]: 0x%x\n", &a[2]); 
    printf("&E[2]-E: 0x%x\n", &a[2] - a); 
    return 1; 
} 

Quando compilate ed eseguite i risultati sono seguenti:

 E: 0xbf8231f8 
    &E[2]: 0xbf823200 
&E[2]-E: 0x2 

comprendo il risultato di & E [2] cui è 8 più l'indirizzo dell'array, poiché indicizzato da 2 e di tipo int (4 byte sul mio sistema a 32 bit), ma non riesco a capire perché l'ultima riga è 2 anziché 8?

Inoltre, che tipo di l'ultima riga dovrebbe essere - un numero intero o un puntatore intero?

Mi chiedo se è il sistema di tipo C (un tipo di fusione) che fa questo capriccio?

+0

Questo è quasi un duplicato di http://stackoverflow.com/questions/759663/pointer-arithmetic-in-c – finnw

+0

Che dire printf ("E: 0x% x \ n", &a); – dashesy

risposta

10

Bisogna ricordare ciò che l'espressione a[2] davvero mezzi . È esattamente equivalente a *(a+2). Tanto è vero che è perfettamente legale scrivere 2[a], con effetto identico.

Affinché funzioni e abbia senso, l'aritmetica del puntatore tiene conto del tipo di oggetto puntato. Ma questo è curato dietro le quinte. Puoi semplicemente utilizzare gli offset naturali nei tuoi array, e tutti i dettagli funzionano.

La stessa logica si applica alle differenze di puntatore, che spiega il risultato di 2.

Sotto il cofano, nel tuo esempio l'indice viene moltiplicato per sizeof(int) per ottenere un offset di byte che viene aggiunto all'indirizzo di base dell'array. Esporti quel dettaglio nelle tue due stampe degli indirizzi.

+1

... o 2 ["divertente"]. –

8

Quando si sottrae i puntatori dello stesso tipo, il risultato è il numero di elementi e non il numero di byte. Questo è di progettazione in modo da poter facilmente indicizzare matrici di qualsiasi tipo. Se si desidera il numero di byte, inserire gli indirizzi in char *.

5

La linea & E [2] -2 sta facendo puntatore sottrazione, non integer sottrazione. La sottrazione del puntatore (quando entrambi i puntatori puntano a dati dello stesso tipo) restituisce la differenza degli indirizzi divisi per la dimensione del tipo a cui puntano. Il valore di ritorno è un int.

per rispondere alla tua domanda "update", ancora una volta, l'aritmetica dei puntatori (questo puntatore oltre il tempo) è in corso. È fatto in questo modo in C per rendere più facile "indicizzare" una porzione di dati contigui puntati dal puntatore.

+1

Il valore di ritorno è un int, non un * * – paxdiablo

+0

Scusa, momento biondo ... hai ragione. – marcog

2

Potreste essere interessati a Pointer Arithmetic In C domande e risposte.

In pratica, + e - gli operatori tengono conto della dimensione dell'elemento quando vengono utilizzati sui puntatori.

0

Se volete vedere la differenza di byte, dovrete un tipo che è 1 byte in termini di dimensioni, come questo:

printf("&E[2]-E:\t0x%x\n",(char*)(&a[2])-(char*)(&a[0])) 
1

Quando aggiungendo e sottraendo i puntatori in C, si utilizza la dimensione di il tipo di dati piuttosto che gli indirizzi assoluti.

Se si dispone di un puntatore a int e aggiungere il numero 2 ad esso, si avanzerà 2 * sizeof (int). Allo stesso modo, se sottrai due puntatori int, otterrai il risultato in unità di sizeof (int) piuttosto che la differenza degli indirizzi assoluti.

(Avere puntatori utilizzando la dimensione del tipo di dati è molto conveniente, in modo che per esempio può semplicemente utilizzare p++ invece di dover specificare la dimensione del tipo ogni volta:. p+=sizeof(int))

7

Quando si incrementa il puntatore di 1 (p + 1), quindi puntatore punta al prossimo indirizzo valido aggiungendo (p + sizeof (Tipo)) byte a p. (Se il tipo è int allora p + sizeof (int))

logica simile vale per p-1 anche (ovviamente sottrarre in questo caso).

Se basta applicare tali principi qui:

In termini semplici:

a[2] can be represented as (a+2) 
a[2]-a  ==> (a+2) - (a) ==> 2 

Così, dietro la scena,

a[2] - a[0] 
==> {(a+ (2* sizeof(int))) - (a+0) }/sizeof(int) 
==> 2 * sizeof(int)/sizeof(int) ==> 2 
1

Ri: "In aggiunta, quale tipo di ultima riga dovrebbe essere? Un numero intero, o un puntatore intero ??"

un numero intero/numero. per lo stesso motivo che il: Oggi - 1 aprile = numero. Non date

+0

elegante davvero. – Pwn