Perché la dimensione di un parametro di matrice non è la stessa di main?


104

Perché la dimensione di un array non è inviata come parametro la stessa di main?

#include <stdio.h>

void PrintSize(int p_someArray[10]);

int main () {
    int myArray[10];
    printf("%d\n", sizeof(myArray)); /* As expected, 40 */
    PrintSize(myArray);/* Prints 4, not 40 */
}

void PrintSize(int p_someArray[10]){
    printf("%d\n", sizeof(p_someArray));
}

Risposte:


103

Un tipo di matrice viene convertito implicitamente in un tipo di puntatore quando lo si passa a una funzione.

Così,

void PrintSize(int p_someArray[10]) {
    printf("%zu\n", sizeof(p_someArray));
}

e

void PrintSize(int *p_someArray) {
    printf("%zu\n", sizeof(p_someArray));
}

sono equivalenti. Quindi quello che ottieni è il valore disizeof(int*)


1
In C ++ è possibile passare la matrice per riferimento alla funzione, ma non è possibile farlo in C.
Prasoon Saurav

13
Dovresti passare la dimensione dell'array come parametro separato. Quindi la dimensione dell'array sarebbe sizeof (* p_someArray) * length
Aric TenEyck

13
Minor nit: l' sizeofoperatore restituisce un oggetto di tipo size_t, quindi dovresti stamparlo con %zu(C99), o inviarlo a intse usi %dcome sopra nelle tue printfchiamate.
Alok Singhal,

4
L'affermazione di Alok è corretta. L'utilizzo di un identificatore di formato errato in printf (..) è UB.
Prasoon Saurav

1
@ Chris_45: C non ha riferimenti, ma in C si può passare un array puntatore l'intero array come in: void PrintSize(int (*p_someArray)[10]). L'interno della funzione è possibile accedere la matrice utilizzando operatore dereference *: sizeof(*p_someArray). Ciò avrà lo stesso effetto dell'uso dei riferimenti in C ++.
AnT

18

È un puntatore, ecco perché è un'implementazione comune passare la dimensione dell'array come secondo parametro alla funzione


16

Come altri hanno affermato, gli array decadono in puntatori al loro primo elemento quando vengono usati come parametri di funzione. Vale anche la pena notare che sizeof non valuta l'espressione e non richiede parentesi quando viene utilizzato con un'espressione, quindi il tuo parametro non viene effettivamente utilizzato affatto, quindi puoi anche scrivere sizeof con il tipo piuttosto che il valore.

#include <stdio.h>

void PrintSize1 ( int someArray[][10] );
void PrintSize2 ( int someArray[10] );

int main ()
{
    int myArray[10];
    printf ( "%d\n", sizeof myArray ); /* as expected 40 */
    printf ( "%d\n", sizeof ( int[10] ) ); /* requires parens */
    PrintSize1 ( 0 ); /* prints 40, does not evaluate 0[0] */
    PrintSize2 ( 0 ); /* prints 40, someArray unused */
}

void PrintSize1 ( int someArray[][10] )
{
    printf ( "%d\n", sizeof someArray[0] );
}

void PrintSize2 ( int someArray[10] )
{
    printf ( "%d\n", sizeof ( int[10] ) );
}

12

Quindi, dovrai passare la lunghezza dell'array come secondo parametro. Quando si scrive codice, in cui entrambi si dichiara un array di dimensione costante e successivamente si passa quell'array a una funzione, è un problema avere la costante di lunghezza dell'array in diversi punti del codice ...

K&R in soccorso:

#define N_ELEMENTS(array) (sizeof(array)/sizeof((array)[0])) 

Quindi ora puoi fare ad esempio:

int a[10];
...
myfunction(a, N_ELEMENTS(a));

cosa succede se la dimensione dell'array non è disponibile in fase di codifica, ma disponibile solo in fase di esecuzione? Esiste un altro modo per calcolare la dimensione dell'array senza codificarne la dimensione?
weefwefwqg3

Il metodo mostrato funziona solo quando la dichiarazione dell'array è "in view". In tutti gli altri casi, devi passare manualmente la lunghezza dell'array.
SC Madsen

5

Perché gli array decadono in puntatori quando vengono passati come parametri. Questo è il modo in cui funziona il C, anche se puoi passare "array" in C ++ per riferimento e superare questo problema. Nota che puoi passare array di dimensioni diverse a questa funzione:

 // 10 is superfluous here! You can pass an array of different size!
void PrintSize(int p_someArray[10]);

5

Il comportamento che hai trovato è in realtà una grande verruca nel linguaggio C. Ogni volta che dichiari una funzione che accetta un parametro di matrice, il compilatore ti ignora e cambia il parametro in un puntatore. Quindi queste dichiarazioni si comportano tutte come la prima:

void func(int *a)
void func(int a[])
void func(int a
typedef int array_plz[5];
void func(array_plz a)

a sarà un puntatore a int in tutti e quattro i casi. Se passi un array a func, decadrà immediatamente in un puntatore al suo primo elemento. (Su un sistema a 64 bit, un puntatore a 64 bit è due volte più grande di un int a 32 bit, quindi il rapporto sizeof restituisce 2.)

L'unico scopo di questa regola è mantenere la compatibilità all'indietro con i compilatori storici che non supportano il passaggio di valori aggregati come argomenti di funzione.

Ciò non significa che sia impossibile passare un array a una funzione. Puoi aggirare questa verruca incorporando l'array in una struttura (questo è fondamentalmente lo scopo dello std :: array di C ++ 11):

struct array_rly {
int a[5];
};
void func(struct array_rly a)
{
printf("%zd\n", sizeof(a.a)/sizeof(a.a[0]));  /* prints 5 */
}

o passando un puntatore all'array:

void func(const int (*a)[5])
{
printf("%zd\n", sizeof(*a)/sizeof((*a)[0]));  /* prints 5 */
}

Nel caso in cui la dimensione dell'array non sia una costante del tempo di compilazione, è possibile utilizzare la tecnica pointer-to-array con array a lunghezza variabile C99:

void func(int n, const int (*a)[n])
{
printf("%zd\n", sizeof(*a)/sizeof((*a)[0]));  /* prints n */
}

4

In c ++ puoi passare un array per riferimento proprio per questo scopo:

void foo(int (&array)[10])
{
    std::cout << sizeof(array) << "\n";
}

1
Come questo aiuterebbe con una domanda C?
alk

3

Nel linguaggio C, non esiste un metodo per determinare la dimensione di un array sconosciuto, quindi è necessario passare la quantità e un puntatore al primo elemento.


2
In generale, dovresti sempre passare la dimensione (numero di elementi) di un array insieme a un array a una funzione, a meno che tu non abbia altri mezzi per determinarne la dimensione (ad esempio, un carattere di terminazione nullo alla fine degli char[]array di stringhe).
David R Tribble

Per favore, cos'è un " array sconosciuto "?
alk

3

Non è possibile passare array alle funzioni.

Se si desidera veramente stampare la dimensione, è possibile passare un puntatore a un array, ma non sarà affatto generico poiché è necessario definire anche la dimensione dell'array per la funzione.

#include <stdio.h>

void PrintSize(int (*p_anArray)[10]);

int main(void) {
    int myArray[10];
    printf("%d\n", sizeof(myArray)); /* as expected 40 */
    PrintSize(&myArray);/* prints 40 */
}

void PrintSize(int (*p_anArray)[10]){
    printf("%d\n", (int) sizeof(*p_anArray));
}

0

Il comportamento è di progettazione.

La stessa sintassi nella dichiarazione dei parametri di funzione significa cose completamente diverse rispetto alla definizione delle variabili locali.

Il motivo è descritto in altre risposte.


0

Nel linguaggio C, quando si passa l'array come argomento alla funzione, viene automaticamente convertito in puntatore, l'array che passa da una funzione all'altra funzione è noto come chiamata per riferimento. Questo è il motivo per cui la funzione chiamata riceve solo il puntatore che punta al primo elemento della funzione. Questo è il motivo

fun (int a []) è simile a fun (int * a);

quindi quando si stampa la dimensione dell'array stamperà la dimensione del primo elemento.


In C non c'è " chiamata per riferimento ".
alk

" quando stampi la dimensione dell'array, stamperà la dimensione del primo elemento. " no, stampa la dimensione di un puntatore.
alk

-1

Nella programmazione 'C' la lingua 'sizeof ()' è l'operatore e restituisce la dimensione dell'oggetto in byte. L'argomento dell'operatore 'sizeof ()' deve essere un tipo di valore di sinistra (intero, numero float, struct, array Quindi se vuoi conoscere la dimensione di un array in byte puoi farlo in modo molto semplice: usa l'operatore 'sizeof ()' e per il suo argomento usa il nome dell'array.Ad esempio:

#include <stdio.h>

main(){

 int n[10];
 printf("Size of n is: %d \n", sizeof(n)); 

}

L'output su un sistema a 32 bit sarà: La dimensione di n è: 40 Perché ineteger su un sistema a 32 è 4 byte Su 64x è 8 byte In questo caso abbiamo 10 numeri interi dichiarati in un array Quindi il risultato è '10 * sizeof ( int)'.

Alcuni suggerimenti:

Se abbiamo un array dichiarato come questo 'int n [] = {1, 2, 3, ... 155 ..};'. Quindi vogliamo sapere quanti elementi sono memorizzati in questo array. Usa questo algoritmo:

sizeof (name_of_the_array) / sizeof (array_type)

Codice: #include

principale(){

int n[] = { 1, 2, 3, 44, 6, 7 };
printf("Number of elements: %d \n", sizeof(n) / sizeof(int));
return 0;

}


2
Benvenuto in StackOverflow e grazie per aver scritto una risposta. Sfortunatamente, questo non risponde alla domanda, che specificamente riguarda la differenza tra sizeof(n)per una variabile locale e sizeof(arg)per un argomento di una funzione, anche se entrambi sono apparentemente di tipo int[10].
MicroVirus

-3

Gli array sono di dimensioni limitate. Per la maggior parte, un array è un puntatore alla memoria. La dimensione nella tua dichiarazione dice solo al compilatore quanta memoria allocare per l'array - non è associata al tipo, quindi sizeof () non ha niente su cui andare.


3
Spiacenti, questa risposta è fuorviante. Né sono array "di dimensioni vaghe", né sono "puntatori alla memoria". Gli array hanno una dimensione molto esatta e le posizioni in cui un nome di array sta per un puntatore al suo primo elemento sono specificate con precisione dallo standard C.
Jens
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.