2011-09-08 1 views
18
#include<stdio.h> 
main() 
{ int x[3][5]={{1,2,10,4,5},{6,7,1,9,10},{11,12,13,14,15}}; 


printf("%d\n",x); 
printf("%d\n",*x); } 

Qui prima printf stamperà l'indirizzo del primo elemento. Quindi perché non il secondo printf stampa il valore all'indirizzo x i.e il primo valore. Per stampare il valore ho bisogno di scrivere ** x.Spiega per favore l'ambiguità nei puntatori in C?

+0

Sei sicuro prima printf stamperà l'indirizzo piuttosto che il valore ?? –

risposta

26

Per i puntatori, x[0] corrisponde a *x. Ne consegue che lo *x[0] è lo stesso di **x.

In *x[0]:

x è un int[3][5], che viene convertito in int(*)[5] quando usato nell'espressione. Quindi x [0] è lvalue di tipo int[5] (la prima "riga" a 5 elementi), che viene nuovamente convertita in int* e trasferita al suo primo elemento.

*x viene valutata sulla stessa linea, tranne la prima dereferenzia avviene con un asterisco (al contrario di indicizzazione), e non c'è secondo dereferenziare, quindi si finisce con Ivalue di tipo int[5], che è passato printf come puntatore al suo primo elemento.

+0

sì, ma ottengo l'indirizzo quando stampo "x" così quando eseguo l'operazione * x dovrei ottenere il valore memorizzato a quell'indirizzo ... – dejavu

+0

Sì e no. Ottieni veramente il valore memorizzato all'indirizzo, questo è il "lvalue di tipo' int [5] '" di cui stavo parlando. Tuttavia, gli array non sono di prima classe in C, sono passati alle funzioni come puntatori al loro primo elemento. Quindi 'printf' ottiene il puntatore al primo' int' del 5, che ha lo stesso indirizzo dell'indirizzo del primo elemento di 'x'. IOW, '(void *) x == (void *) * x' e questo è ciò che vedi. – jpalecek

+0

Ho modificato la domanda .. questo era il mio dubbio ... quello era un errore di stampa .. – dejavu

-1

Pensa a un array 2-d come una matrice di puntatori, con ogni elemento nell'array che punta al primo elemento in un altro array. Quando si dereference x, si ottiene il valore che si trova nella posizione di memoria puntata da x ... un puntatore al primo int in un array di int s. Quando si dereferenzia quel puntatore, si otterrà il primo elemento.

+3

Questo non è accurato. Si può certamente disporre di un efficace array 2D bidimensionale con una serie di puntatori, ma la memoria effettiva è solo riga per fila in sequenza, con il dereferenziamento fatto per moltiplicazione. – Yuliy

+0

@Yuliy: Capisco che non è come viene implementato, ma è un modo semplice per capire perché è necessario dereferenziare due volte. – Daniel

+1

@Daniel: il punto di Yuliy si alza. C'è già abbastanza confusione tra i neofiti di C su questo, e già troppi tentativi di allocare un "array bidimensionale" come una schiera di puntatori, che qualsiasi rischio di favorire questo fraintendimento dovrebbe essere evitato. –

4

Gli array, quando utilizzati come argomenti per le funzioni, decadono in puntatori del primo elemento dell'array. Detto questo, il tipo di oggetto a cui decade x è un puntatore al primo sub-array, che è un puntatore a un array di int o sostanzialmente int (*)[5]. Quando si chiama printf("%d\n",*x), non si invia un valore intero a printf, ma piuttosto un puntatore al primo sub-array di x. Poiché tale sub-array decadrà anche in un puntatore al primo elemento della sotto-matrice, è possibile eseguire **x per dereferenziare il puntatore successivo e ottenere il primo elemento del primo sub-array di x. Questo è effettivamente la stessa cosa di *x[0], che per precedenza dell'operatore indicizzerà il primo sotto-array di x, quindi diterrà il puntatore al primo elemento della sotto-matrice in cui il primo sub-array decadrà.

0

A causa del tipo di *x è "puntatore a matrice di 5 ints". Quindi, è necessario un altro dereference per ottenere il primo elemento

PS:

#include <typeinfo> 
#include <iostream> 

typedef int arr[5]; // can't compile if put arr[4] here 
void foo(arr& x) 
{ 
} 

int main() 
{ 
    int x[3][5]={{1,2,10,4,5},{6,7,1,9,10},{11,12,13,14,15}}; 

    std::cout << typeid(*x).name() << std::endl;// output: int [5] 

    foo(x[0]); 
    return 0; 
} 

+0

Il tipo di '* x' è" puntatore a 'int'" ('int *'). È 'x' stesso, dopo che il tipo di array decade in un puntatore in un'espressione, che ha tipo" puntatore all'array di 5 'int's". –

+0

Erm, '* x' ha tipo" array di 5 ints ", quindi ho sbagliato leggermente. Nella maggior parte dei contesti, questo decade per digitare "puntatore su int". Di certo non ha tipo "puntatore a serie di 5 pollici" in alcuna interpretazione. –

+0

Sì, avevo cambiato il mio messaggio originale e aggiunto alcune "prove". – qehgt