2014-12-25 11 views
5

Sono nuovo ai puntatori e alle nozioni di base di apprendimento dei puntatori. Voglio sapere la differenza tra * ptr e * (& ptr + 1) dal codice seguente.Differenza tra * ptr e * (& ptr + 1)

#include<stdio.h> 
int main() 
{ 
    int a[3] = {1, 2, 3}; 
    int *ptr = a; 

    printf("*ptr = %d\n",*ptr); 
    printf("&ptr = %p\n",&ptr); 

    printf("(&ptr + 1) = %p\n",(&ptr + 1)); 
    printf("*(&ptr + 1) = %d\n",*(&ptr + 1)); 

    return 0; 
}  

Dalla mia analisi gcc produce il seguente output,

*ptr = 1 // as ptr = a, Ultimately *ptr will print the first value of array i.e. 1 
&ptr = 0x7fffa7e97788 // Starting Address of array or address of first element 
(&ptr + 1) = 0x7fffa7e97790 //address of next element in the array 
*(&ptr + 1) = 1 // I want to know how this is getting dereffered 

Grazie in anticipo.

+0

Che dimensione è 'int', nel proprio ambiente? –

+0

La dimensione di int è 4 byte – arahan567

+0

[questo] (http://stackoverflow.com/a/24468853/2455888) può aiutare a capire questo graficamente. – haccks

risposta

8

&ptr è l'indirizzo della variabile pointer ptr. Questo indirizzo non è correlato all'indirizzo dell'array.

*(&ptr + 1) è un comportamento non definito perché &ptr + 1 è un passo dopo l'indirizzo di ptr. Il dereferenziamento di un tale puntatore produce un comportamento indefinito.

Quello che probabilmente intendevi era *(ptr + 1).

+0

Sto usando Ubuntu a 64 bit e la differenza tra gli indirizzi è esattamente di 8 byte che è a 64 bit, e probabilmente sto dando l'indirizzo successivo come puoi vedere ma non l'indirizzo passato se uso (& ptr + 1). mi puoi spiegare perché? – arahan567

+0

Non capisco questa domanda. Cosa intendi per "indirizzo passato"? Perché dovresti aspettarti di vedere un indirizzo più piccolo (= passato?) Se aggiungi 1 a un puntatore? Capisci che '& ptr + 1' punta a nulla? – usr

+0

Grazie mille per averlo capito, ho solo avuto un po 'di confusione con l'aritmetica degli indirizzi con la tua spiegazione l'ho risolto. – arahan567

6

Sembra che il compilatore collocato oggetti definiti in pila seguente modo

-------------------------------- 
| ptr | a[0] | a[1] | a[2] | 
-------------------------------- 

Così &ptr è l'indirizzo in cui è allocato ptr. &ptr + 1 è il prossimo indirizzo dopo ptr e allo stesso tempo è l'indirizzo di [0].

Prendere in considerazione che non è specificato in quale ordine il compilatore deve posizionare le variabili locali nello stack.

Inoltre sembra che nell'ambiente in cui il programma è stato compilato sizeof(int *) che corrisponde to sizeof(*(&ptr + 1)) è uguale a sizeof(int) e, a sua volta pari a 4. Oppure sizeof(int *) è pari a 8, ma sizeof(int) è pari a 4. Come si utilizza formato specificatore %d in printf per espressione *(&ptr + 1) quindi viene emesso esattamente un [0].

Tra l'altro è possibile verificare se questo schema corrisponde l'espletamento effettivo delle variabili stampando

printf("(&ptr + 1) = %p\n", &ptr + 1); 
printf("(&a[0]) = %p\n", &a[0]); 

Se gli indirizzi non saranno uguali allora vuol dire che c'è qualche valore arbitrario all'indirizzo &ptr + 1 quello non corrisponde a [0].

Per quanto riguarda la domanda nel titolo del tuo post

differenza tra * ptr e * (& ptr + 1)

poi *ptr corrisponde a a[0] mentre si utilizza l'espressione *(&ptr + 1) risultati indefiniti comportamento perché si sta tentando di dereferenziare l'indirizzo dopo ptr.

+0

(& ptr + 1 è l'indirizzo successivo del ptr e allo stesso tempo è l'indirizzo di [0])? per favore mi spieghi come lo fa il compilatore? – arahan567

+0

@ arahan567 Il compilatore posiziona le variabili nello stack una dopo l'altra e, se necessario, allinea i loro indirizzi. Sembra che il compilatore abbia posizionato l'array dopo ptr senza alcun byte di padding dopo ptr. Quindi l'array inizia all'indirizzo dopo ptr. –

+0

Poiché l'OP riporta sizeof (int) = 4 e sizeof (int *) == 8, potrebbe avere senso dare a 'ptr' una sezione più grande nel diagramma. (ad esempio, crea la casella contenente ptr due volte più grande della casella contenente un [0]) –

1

ptr è un puntatore e indica una posizione di memoria valida nel tuo caso.

&ptr è l'indirizzo del puntatore e può essere assegnato a un doppio puntatore

int **ptr1 = &ptr; 

Else l'indirizzo del primo elemento è dato semplicemente ptr.

Se si vuole analizzare attraverso l'array poi hanno

for(i=0;i<4;i++) 
{ 
printf("Value %d is stored in %p\n",ptr[i],(void *)(ptr+i)); 
} 

(&ptr+1) essere dereferenziato porta ad un comportamento indefinito come questo non è la memoria che viene allocata da voi. &ptr è sotto il tuo controllo, non il luogo dopo di esso, cioè &ptr+1

0

Bene, questo sembra interessante. In primo luogo, come sapresti, *ptr fornisce il valore di a[0], ptr contiene l'indirizzo di a[0] e &ptr è l'indirizzo di ptr variabile di puntatore intero.

Con questo in mente, quando si stampa *ptr, il valore di a[0] cioè 1 otterrà stampata, (&ptr+1) sarebbe indirizzo un passo dopo l'indirizzo di ptr e *(&ptr+1) sarebbe stampare il valore all'indirizzo (&ptr+1). Nel codice sopra riportato, l'indirizzo di a[0] è immediatamente dopo l'indirizzo di ptr (ovvero &ptr). Quindi, quando si stampa *(&ptr+1), si stampa 1 perché &ptr+1 punta a a[0]. Questo dipende dalla memoria assegnata alle variabili.

Dichiarare le variabili precedenti come globali e *(&ptr+1) stamperebbe il valore di zero (se '* (& ptr + 1)' non punta a nessuna posizione perché le variabili globali sono inizializzate a zero). Inoltre, osserva la differenza nell'indirizzo assegnato alle variabili, quando dichiarato come globale e locale. Spero che questo ti sia d'aiuto.

+0

Grazie shiva kumar hai ragione quando le variabili globali diventano la parte del segmento di dati che otterremo il valore spazzatura. Ma qui il caso è con il segmento dello stack quindi probabilmente penso che non ci saranno problemi con la memoria. – arahan567

+0

Le variabili globali sono inizializzate a zero e non a valore errato. – Shivakumar

+0

Grazie per aver corretto il mio errore. – arahan567

Problemi correlati