2012-07-23 13 views
10

Voglio ottenere la lunghezza di un array, ad esempio int array[] = {1, 2, 3, 4}. Ho usato sizeof per farlo.Perché sizeof (param_array) è la dimensione del puntatore?

int length(int array[]) 
{ 
    return sizeof(array)/sizeof(int); 
} 

int main() 
{ 
    int array[] = {1, 2, 3, 4}; 
    printf("%d\n", length(array)); // print 1 
    printf("%d\n", sizeof(array)/sizeof(int)); // print 4 
} 

Quindi, perché la sizeof(array) nella funzione length restituisce la dimensione del puntatore del array? Ma nella funzione main, funziona.

E, come devo modificare la funzione length per ottenere la lunghezza di una matrice?

+1

Sì, so che questa è una domanda C++, ma contiene informazioni molto utili riguardanti C così: http://stackoverflow.com/questions/4810664/how-do-i-use-arrays-in -c – chris

risposta

18

Una regola C specifica dice che per i parametri di funzione, i tipi di array sono regolati a tipi di puntatore.Ciò significa:

int length(int array[]);

è equivalente a

int length(int *array);

Così, quando si calcola la sizeof la matrice in realtà si sta calcolando la dimensione del puntatore.

(C99, 6.7.5.3p7) "Una dichiarazione di un parametro come 'array di tipo' è regolato a 'puntatore per assegnare il tipo', dove le qualificazioni tipo (se presenti) sono quelli specificati all'interno il [e] della derivazione del tipo di matrice. "

+4

... e l'implicazione di ciò è che non è possibile riscrivere 'length()' per funzionare come si desidera - se una funzione ha bisogno di conoscere la dimensione di un array, deve essere passata a quella funzione come parametro separato. – caf

+0

@caf Sono d'accordo con te. Per ulteriori informazioni, ha senso farlo in questo modo, specialmente quando si utilizza un processore ARM con registri a r0, r1, r2, r3 a 32 bit. Quindi un puntatore può essere passato in r0 piuttosto che dover usare lo stack. –

2

C non memorizza i metadati di runtime sulla dimensione di un array con la variabile. Dovrai conservarlo da qualche parte.

Una variabile di tipo int [] nel contesto del metodo lunghezza è solo un puntatore a un blocco di memoria. Ecco perché la dimensione è uguale alla dimensione di qualsiasi altro puntatore sul tuo sistema.

Quando sizeof ha accesso alla matrice al momento della compilazione (come nel principale funzione) sarà invece restituire il numero di byte occupati dalla matrice.

+1

"Una variabile di tipo int [] è solo un puntatore a un blocco di memoria" - che non è corretto nel caso generale. Una variabile di tipo 'int []' * è * un blocco di memoria. Non è un puntatore. Gli unici contesti in cui 'int []' sta per un puntatore è la dichiarazione dei parametri di funzione ed è un * caso speciale *. – AnT

+0

Chiarito che si tratta di un puntatore * nel contesto del metodo length() *. Grazie per la segnalazione. –

3

Nel programma principale, il compilatore conosce la lunghezza dell'array. Nella subroutine, non è così. In particolare, in una subroutine, un parametro di tipo int[] è identico a un parametro di tipo int *. Nel programma principale, d'altra parte, array ha tipo int[4]. (È possibile verificare ciò provando a assegnare un altro valore anel lato main. Il compilatore si lamenterà.)

0

Poiché la matrice variabile all'interno della lunghezza non è uguale a quella esterna. Devi mantenere la dimensione di (array)/sizeof (int) nella funzione principale.

4

L'array decade in un puntatore quando lo si passa in una funzione.

0

modificare il codice in modo che length può ottenere la lunghezza dell'array, trasformarlo in una macro:

#define length(x) (sizeof(x)/sizeof(*x)) 

Per il vostro esempio di codice, questo si comporterà come previsto.

Si noti che questo sarà solo funziona su array allocati staticamente e solo quando viene chiamato utilizzando l'array originale (non funzionerà quando si utilizza un puntatore all'array). Questo perché quando si scrive sizeof(x) dove x è un puntatore a un array, il compilatore lo interpreta letteralmente. Non ha alcun modo di mappare x indietro alla matrice a cui punta prima di valutare lo sizeof.

1

Se si desidera che length sia consapevole della dimensione effettiva dell'array passato, è necessario che tali informazioni vengano passate, come dicono tutti. Ma è possibile per poter ricevere un riferimento alla matrice con le informazioni anche built-in:

int length(int n, int (* array)[n]) 
{ 
    return sizeof(*array)/sizeof(int); 
} 

int main() 
{ 
    int array[] = {1, 2, 3, 4}; 
    printf("%d\n", length(4, &array)); // print 1 
    printf("%d\n", sizeof(array)/sizeof(int)); // print 4 
} 

non so cosa buona che in realtà si fa, però, dal momento che la dimensione è già previsto nella primo posto. Ma vedi che l'operatore sizeof funziona come tu vuoi in questo caso.

4

Come hanno notato gli altri responder, una funzione dichiarata per prendere un array viene compilata come se avesse un puntatore.

Il modo più comune in cui ho visto il metodo di lunghezza è con #define, ma se giochi con i modelli, puoi far funzionare la tua funzione.

template <size_t _Size> inline int length(int(& array)[_Size]) 
{ 
    //return sizeof(array)/sizeof(int); 
    return _Size; 
}; 

int array[] = {1, 2, 3, 4}; 
printf("%d\n", length(array)); // print 4 

Con la vostra gamma di lunghezza 4, questo viene compilato come un metodo che accetta un array di lunghezza 4, e restituisce una statica 4. Questo ha anche il vantaggio che se si tenta di passare qualcosa che non è una matrice, il compilatore darà un errore, mentre il metodo #define no.

int* foo = array; 
printf("%d\n", length(foo)); 
    // error C2784: 'int length(int (&)[_Size])' : could not deduce template 
    //  argument for 'int (&)[_Size]' from 'int *' 
    // test.cpp(56) : see declaration of 'length' 
+1

Domanda taggata C, non C++. – jxh

+0

Ah, giusto. Oh beh, forse lo troverà comunque utile. –

Problemi correlati