2011-10-06 20 views
5

Ho la seguente applicazione di test:Perché un char * viene trattato come un char ** in C?

#include <stdlib.h> 
#include <string.h> 
#include <stdio.h> 

int main(void){ 
    char buf[512]; 
    buf[0]= 0x1; 
    buf[1]= 0x2; 
    char *temp1 = &buf; 
    char *temp2 = buf; 
    char *temp3 = &buf[0]; 
    printf("temp1:%p, temp2:%p, temp3:%p\n",temp1,temp2,temp3); 
    printf("0 = %d, %d, %d\n",temp1[0],temp2[0],temp3[0]); 
    printf("1 = %d, %d, %d\n",temp1[1],temp2[1],temp3[1]); 
    return; 
} 

Si compila con un avvertimento:

Ma quando l'eseguo, tutti e tre i puntatori si comportano allo stesso.

./testptr 
temp1:0x7fff3a85f220, temp2:0x7fff3a85f220, temp3:0x7fff3a85f220 
0 = 1, 1, 1 
1 = 2, 2, 2 

so che buf == &buf[0], ma perché &buf == &buf[0]? Non dovrebbe &buf essere un char**?

+1

'& buf' è in realtà un' char (*) [512] '(un puntatore a una matrice' char' di 512 elementi). Non sono esattamente la stessa cosa. –

+0

Hai cambiato il tuo codice tra catturare l'output del compilatore e incollare il codice nella domanda. Il problema è sulla linea 9 ora. –

+0

Siamo spiacenti, hai appena aggiunto una nuova riga – austinmarton

risposta

3

Tutti i puntatori si comportano allo stesso perché dichiarato tutti loro di essere char*. C è tipizzato staticamente in modo che il tipo sia associato alla variabile e non al valore.

Ora che la parte relativa al comportamento è stata spiegata, abbiamo solo bisogno di scoprire perché hanno effettivamente lo stesso valore (come per% p printf). Bene, questo è solo un artefatto di puntatori implementati come indirizzo di memoria da GCC (gli offset e il dimensionamento che fanno un * differiscono da un ** sono tutti gestiti dal sistema di tipi/compilatore dietro le quinte).Si noti che, come una delle cose più sospette che emette avvisi, è probabile che si tratti di un comportamento indefinito o almeno una cattiva pratica :)

2

Gli array non sono puntatori, sebbene possano essere utilizzati più o meno allo stesso modo. È capitato di aver trovato un aspetto in cui la semantica degli array e dei puntatori differisce.

+0

L'ho scoperto quando ho accidentalmente passato '& buf' invece di' buf' come secondo argomento di tipo 'void *' alla funzione [recv] (http://linux.die.net/man/2/recv) . È possibile che questo potrebbe causare un problema anche se il mio esempio sopra non lo illustra? – austinmarton

+0

@austinmarton: preferisco sbagliare dalla parte della paranoia quando si tratta di avvisi del compilatore C – hugomg

+0

@missingno: Fair call. Nella mia applicazione originale l'errore è stato passato come puntatore vuoto, quindi non è stato generato alcun avviso. – austinmarton

1

È possibile ricavare dall'algebra degli operatori * e &.

  • sappiamo che buf è l'indirizzo dell'elemento 0-esimo dell'array buf

  • sappiamo che &buf[0] è anche l'indirizzo dell'elemento 0-esimo

  • per definizione buf[0] è equivalente a *(buf+0)

  • e &(*(a)) equivale a a.

Quindi, &buf[0] diventa &(*(buf+0)) che è buf.

Aggiornamento

Qui, cerchiamo di stenderlo come una prova.

  1. &buf[0] Dato.
  2. &(buf[0]) da regole di precedenza C con (s '
  3. &((*(buf+0))) perché buf[0] == *(buf+0)).
  4. &(*(buf+0)) eliminando parentesi estranee
  5. buf QED
+3

Sono d'accordo con quello che stai dicendo ('buf == & buf [0]'), ma non è proprio quello che ti sto chiedendo ('& buf == buf'?). – austinmarton

+0

@austinmarton, segui i passaggi: sono una prova che, sì, '& buf' è equivalente a' buf'. –

+1

@Charlie: No, la dimostrazione dice che '& buf [0]' equivale a 'buf', non che' & buf' sia equivalente a 'buf', che era quello a cui si poneva la domanda. – icktoofay

1

Se si pensa a quale codice viene effettivamente generato dal compilatore quando elabora un array, diventa più chiaro. Il nome buf fa riferimento all'indirizzo del primo elemento (zeroth) dell'array (spazio contiguo per contenere i caratteri). Se guardi l'oggetto alla voce della tabella dei simboli per "buf", troverai l'indirizzo di quel primo elemento. Quando fai riferimento, ad es., Buf [0], il compilatore genera l'indirizzo di buf, più zero volte la dimensione di un carattere. Questo è uguale all'indirizzo di buf stesso.