Por que o tamanho de um parâmetro de array não é o mesmo de main?

104

Por que o tamanho de um array enviado como parâmetro não é igual ao de 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));
}
Chris_45
fonte

Respostas:

103

Um tipo de matriz é convertido implicitamente em tipo de ponteiro quando você o passa para uma função.

Assim,

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

e

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

são equivalentes. Então, o que você obtém é o valor desizeof(int*)

Prasoon Saurav
fonte
1
Em C ++, você pode passar a matriz por referência à função, mas não pode fazer isso em C.
Prasoon Saurav
13
Você precisaria passar o tamanho da matriz como um parâmetro separado. Então, o tamanho da matriz seria sizeof (* p_someArray) * length
Aric TenEyck
13
Minor nit: sizeofoperator retorna um objeto do tipo size_t, então você deve imprimi-lo com %zu(C99), ou convertê-lo intse você usar %dcomo acima em suas printfchamadas.
Alok Singhal
4
A declaração de Alok está correta. Usar o especificador de formato incorreto em printf (..) é UB.
Prasoon Saurav
1
@ Chris_45: C não tem referências, mas em C você pode passar um array por ponteiro para a matriz inteira como em: void PrintSize(int (*p_someArray)[10]). O interior da função você pode acessar a matriz usando operador dereference *: sizeof(*p_someArray). Isso terá o mesmo efeito que usar referências em C ++.
AnT
18

É um ponteiro, por isso é uma implementação comum passar o tamanho do array como um segundo parâmetro para a função

user240312
fonte
16

Como outros afirmaram, os arrays decaem para ponteiros para seu primeiro elemento quando usados ​​como parâmetros de função. Também vale a pena notar que sizeof não avalia a expressão e não requer parênteses quando usado com uma expressão, então seu parâmetro não está sendo usado, então você também pode escrever o sizeof com o tipo ao invés do valor.

#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] ) );
}
Pete Kirkham
fonte
12

Portanto, você precisará passar o comprimento do array como um segundo parâmetro. Quando você está escrevendo um código, no qual você declara uma matriz de tamanho constante e, posteriormente, passa essa matriz para uma função, é uma dor ter a constante de comprimento de matriz aparecendo em vários lugares em seu código ...

K&R para o resgate:

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

Agora você pode fazer, por exemplo:

int a[10];
...
myfunction(a, N_ELEMENTS(a));
SC Madsen
fonte
e se o tamanho da matriz não estiver disponível no momento da codificação, mas apenas no tempo de execução? Existe alguma outra maneira de calcular o tamanho da matriz sem codificar seu tamanho?
weefwefwqg3
O método mostrado só funciona, quando a declaração do array está "à vista". Para todos os outros casos, você deve passar manualmente o comprimento do array.
SC Madsen
5

Porque os arrays se transformam em ponteiros quando são passados ​​como parâmetros. É assim que C funciona, embora você possa passar "matrizes" em C ++ por referência e superar esse problema. Observe que você pode passar matrizes de tamanhos diferentes para esta função:

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

O comportamento que você encontrou é, na verdade, uma grande verruga na linguagem C. Sempre que você declara uma função que recebe um parâmetro de matriz, o compilador o ignora e altera o parâmetro para um ponteiro. Portanto, todas essas declarações se comportam como a primeira:

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

a será um ponteiro para int em todos os quatro casos. Se você passar um array para func, ele imediatamente se tornará um ponteiro para seu primeiro elemento. (Em um sistema de 64 bits, um ponteiro de 64 bits é duas vezes maior que um int de 32 bits, portanto, seu tamanho de proporção retorna 2.)

O único propósito desta regra é manter a compatibilidade retroativa com compiladores históricos que não suportavam a passagem de valores agregados como argumentos de função.

Isso não significa que seja impossível passar um array para uma função. Você pode contornar essa verruga incorporando a matriz em uma estrutura (essa é basicamente a finalidade de std :: array do 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 */
}

ou passando um ponteiro para a matriz:

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

Caso o tamanho do array não seja uma constante de tempo de compilação, você pode usar a técnica de ponteiro para array com arrays de comprimento variável C99:

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

Em c ++, você pode passar um array por referência para este propósito:

void foo(int (&array)[10])
{
    std::cout << sizeof(array) << "\n";
}
Alexandre C.
fonte
1
Como isso ajudaria com uma pergunta C?
alk
3

Na linguagem C, não há nenhum método para determinar o tamanho de um array desconhecido, então a quantidade precisa ser passada, bem como um ponteiro para o primeiro elemento.


fonte
2
Em geral, você deve sempre passar o tamanho (número de elementos) de um array junto com um array para uma função, a menos que você tenha algum outro meio de determinar seu tamanho (por exemplo, um terminador de caractere nulo no final dos char[]arrays de string).
David R Tribble
Por favor, o que é uma " matriz desconhecida "?
alk
3

Você não pode passar matrizes para funções.

Se você realmente deseja imprimir o tamanho, pode passar um ponteiro para um array, mas não será genérico, pois você também precisa definir o tamanho do array para a função.

#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));
}
SR.
fonte
0

O comportamento é por design.

Mesma sintaxe na declaração de parâmetro de função significa algo completamente diferente do que na definição de variável local.

O motivo é descrito em outras respostas.

Pavel Radzivilovsky
fonte
0

Na linguagem C, quando você passa o array como um argumento para a função, ele é automaticamente convertido em ponteiro, o array passando de uma função para outra função é conhecido como chamada por referência. Esta é a razão pela qual a função chamada apenas recebe o ponteiro que aponta para o primeiro elemento da função Esta é a razão

fun (int a []) é semelhante a fun (int * a);

então, quando você imprimir o tamanho do array, ele imprimirá o tamanho do primeiro elemento.

dagrawal
fonte
Em C não há " chamada por referência ".
alk
" quando você imprime o tamanho do array, ele imprime o tamanho do primeiro elemento. " não, ele imprime o tamanho de um ponteiro.
alk
-1

Em 'C' linguagem de programação 'sizeof ()' é o operador e ele retorna o tamanho do objeto em bytes. O argumento do operador 'sizeof ()' deve ser um tipo de valor à esquerda (inteiro, número flutuante, estrutura, matriz ). Portanto, se você quiser saber o tamanho de um array em bytes, pode fazê-lo de maneira muito simples. Basta usar o operador 'sizeof ()' e como argumento o nome do array. Por exemplo:

#include <stdio.h>

main(){

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

}

A saída no sistema de 32 bits será: Tamanho de n é: 40.Porque ineteger no sistema de 32 é de 4 bytes. Em 64x é de 8 bytes. Neste caso, temos 10 inteiros declarados em uma matriz. Portanto, o resultado é '10 * sizeof ( int) '.

Algumas dicas:

Se tivermos uma matriz declarada como esta 'int n [] = {1, 2, 3, ... 155 ..};'. Portanto, queremos saber quantos elementos estão armazenados neste array. Use este alghoritmo:

sizeof (name_of_the_array) / sizeof (array_type)

Código: #include

a Principal(){

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

}

RichardGeerify
fonte
2
Bem-vindo ao StackOverflow e obrigado por escrever uma resposta. Infelizmente, isso não responde à questão, que é especificamente sobre a diferença entre sizeof(n)para uma variável local e sizeof(arg)para um argumento para uma função, embora ambos sejam aparentemente do tipo int[10].
MicroVirus
-3

As matrizes têm tamanhos vagos. Na maior parte, uma matriz é um ponteiro para a memória. O tamanho em sua declaração apenas diz ao compilador quanta memória alocar para o array - não está associado ao tipo, então sizeof () não tem nada para continuar.

plinto
fonte
3
Desculpe, esta resposta é enganosa. Nem são matrizes de "tamanho flexível", nem são "ponteiros para a memória". Os arrays têm um tamanho muito exato e os locais onde um nome de array representa um ponteiro para seu primeiro elemento são especificados com precisão pelo padrão C.
Jens