2016-01-22 16 views
5

Perché se sottraggo da un puntatore un altro puntatore (puntatori interi) senza typecasting il risultato sarà 1 e non 4 byte (come quando è convertito in typ in int entrambi i puntatori). Esempio:Perché la sottrazione del puntatore in C produce un intero?

int a , b , *p , *q; 
p = &b; 
q = p + 1; // q = &a; 
printf("%d",q - p); // The result will be one . 
printf("%d",(int)q - (int)p); // The result will be 4(bytes). The memory address of b minus The memory address of a. 
+2

vostri invoca codice comportamento indefinito. Per la differenza tra puntatori usa 'ptrdiff_t' e l'identificatore appropriato per' printf'. –

+0

È normale, quando fai puntatore = puntatore + 1, aggiunge 1 * sizeof (int *); –

+2

@PierreEmmanuelLallemant: Credo che tu intenda '1 * sizeof (int)', non 'int *'. – ShadowRanger

risposta

3

Perché se se sottraggo da un puntatore un altro puntatore (puntatori interi) senza typecasting il risultato sarà 1 e non 4 byte

Questo è il punto centrale del tipo di dati che un puntatore che punta a . Probabilmente è più semplice guardare un contesto di array come di seguito. Il punto è indipendentemente dal tipo di dati sottostante (in questo caso long o double), è possibile utilizzare l'aritmetica del puntatore per navigare nell'array senza preoccuparsi di come esattamente la dimensione del suo elemento sia. In altre parole, (puntatore + 1) significa puntare sull'elemento successivo indipendentemente dal tipo.

long l[] = { 10e4, 10e5, 10e6 }; 
long *pl = l + 1; // point to the 2nd element in the "long" array. 

double d[] = { 10e7, 10e8, 10e9 }; 
double *pd = d + 2; // point to the 3rd element in the "double" array. 

notare anche nel codice:

int a , b , *p , *q; 
p = &b; 
q = p + 1; // q = &a; <--- NO this is wrong. 

Il fatto che a e b sono dichiarato uno accanto all'altro non significa che a e b sono assegnati uno accanto all'altro in la memoria. Quindi q punta all'indirizzo di memoria accanto a quello di b - ma ciò che è in quell'indirizzo non è definito.

+0

Puntare su un'area non inizializzata è soddisfacente e abbastanza comune. Questo potrebbe precedere '* q = 7' per inizializzare la memoria (variabile). – wallyk

+0

Ma non è sicuramente l'indirizzo di 'a' in questo codice. – artm

+0

Forse non è "a", e sono d'accordo che è estremamente imprudente aspettarsi che lo sia. – wallyk

3

Poiché il ptrdiff_t dal puntatore sottrazione è calcolato rispetto alla dimensione degli elementi puntato. È molto più conveniente in questo modo; per uno, ti dice quante volte puoi incrementare un puntatore prima di raggiungere l'altro puntatore.

3

dove si ha

int a , b , *p , *q; 

Il compilatore può mettere a e b ovunque. Non devono nemmeno essere vicini l'un l'altro. Inoltre, quando si sottrae due puntatori int, il risultato viene ridimensionato in termini di int, non di byte.

4

Secondo il C standard (6.5.6 Operatori additivi)

9 Quando due puntatori vengono sottratti, entrambi si dirigerà verso elementi stesso oggetto matrice, oppure uno dopo l'ultimo elemento di l'array oggetto; il risultato è la differenza dei pedici dei due elementi dell'array ....

Se i due puntatori indicarono elementi dello stesso array poi come è detto nella citazione dalla standard

il risultato è la differenza tra gli indici dei due matrice elementi

Si otterrà il numero di elementi dell'array tra questi due puntatori. È il risultato del cosiddetto aritmetico puntatore.

Se si sottraggono gli indirizzi memorizzati nei puntatori come valori interi, si otterrà il numero corrispondente all'operazione di sottrazione aritmetica.

+0

Quindi la sottrazione tra 'q' e' p' restituisce la 'distanza' tra 'q' e 'p'. Se 'p' punta al primo elemento dell'array e' q' punta all'ultimo. 'q - p' restituisce il numero di elementi dell'array? –

+1

@ Călin Calin, non si indicizza un array 'int' come' array [0] ... array [4] ... array [8] ... 'per tenere conto della dimensione dei dati, vero? Allo stesso modo con il puntatore aritmetico. –

+2

Hai trascurato "o uno dopo l'ultimo elemento" immediatamente dopo il testo in grassetto. 'q - p' è valido. (Ma è stato usato l'identificatore di formato sbagliato). –

2

C non è linguaggio assembly. Quindi i puntatori non sono semplici numeri interi: i puntatori sono ragazzi speciali che sanno indicare altre cose.

È fondamentale il modo in cui i puntatori e l'aritmetica dei puntatori funzionano in C in modo che possano puntare a elementi successivi di un array. Quindi, se scriviamo

int a[10]; 
int *p1 = &a[4]; 
int *p2 = &a[3]; 

poi p1 - p2 sarà 1. Il risultato è 1 perché la "distanza" tra a[3] ed a[4] è uno int. Il risultato è 1 perché 4 - 3 = 1. Il risultato è non 4 (come si potrebbe pensare sarebbe se si sa che int s sono 32 bit sulla macchina) perché non siamo interessanti nel fare linguaggio assembly programmare o lavorare con indirizzi macchina; stiamo facendo una programmazione linguistica di livello superiore con un array, e stiamo pensando in questi termini.

(Ma, sì, a livello di indirizzo della macchina, il modo in cui p2 - p1 viene calcolata comprende tipicamente (< valore grezzo indirizzo in p2 >-< valore di indirizzo prima in p1 >)/sizeof(int).)

+0

Grazie, ho capito la "magia" dietro a ciò. –

Problemi correlati