¿Por qué el tamaño de un parámetro de matriz no es el mismo que dentro de main?


104

¿Por qué el tamaño de una matriz enviada como parámetro no es el mismo que dentro 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));
}

Respuestas:


103

Un tipo de matriz se convierte implícitamente en un tipo de puntero cuando lo pasa a una función.

Entonces,

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

y

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

son equivalentes. Entonces lo que obtienes es el valor desizeof(int*)


1
En C ++ puede pasar la matriz por referencia a la función, pero no puede hacerlo en C.
Prasoon Saurav

13
Debería pasar el tamaño de la matriz como un parámetro separado. Luego, el tamaño de la matriz sería sizeof (* p_someArray) * length
Aric TenEyck

13
Minor nit: el sizeofoperador devuelve un objeto de tipo size_t, por lo que debe imprimirlo con %zu(C99), o enviarlo a intsi usa %dcomo arriba en sus printfllamadas.
Alok Singhal

4
La declaración de Alok es correcta. El uso de un especificador de formato incorrecto en printf (..) es UB.
Prasoon Saurav

1
@ Chris_45: C No hay referencias, pero en C que puede pasar una matriz de puntero a toda la matriz como en: void PrintSize(int (*p_someArray)[10]). El interior de la función que se puede acceder a la matriz mediante el uso del operador eliminar la referencia *: sizeof(*p_someArray). Esto tendrá el mismo efecto que usar referencias en C ++.
el AnT

18

Es un puntero, por eso es una implementación común pasar el tamaño de la matriz como un segundo parámetro a la función


16

Como han dicho otros, las matrices se reducen a punteros a su primer elemento cuando se utilizan como parámetros de función. También vale la pena señalar que sizeof no evalúa la expresión y no requiere paréntesis cuando se usa con una expresión, por lo que su parámetro no se usa en absoluto, por lo que también puede escribir sizeof con el tipo en lugar del 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] ) );
}

12

Por lo tanto, deberá pasar la longitud de la matriz como segundo parámetro. Cuando está escribiendo código, en el que ambos declaran una matriz de tamaño constante y luego pasan esa matriz a una función, es una molestia que la constante de longitud de matriz aparezca en varios lugares de su código ...

K&R al rescate:

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

Entonces ahora puedes hacer, por ejemplo:

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

¿Qué pasa si el tamaño de la matriz no está disponible en el momento de la codificación, pero solo está disponible en el tiempo de ejecución? ¿Hay alguna otra forma de calcular el tamaño de la matriz sin codificar su tamaño?
weefwefwqg3

El método mostrado solo funciona cuando la declaración de la matriz está "a la vista". Para todos los demás casos, debe pasar manualmente la longitud de la matriz.
SC Madsen

5

Porque las matrices se descomponen en punteros cuando se pasan como parámetros. Así es como funciona C, aunque puede pasar "matrices" en C ++ por referencia y solucionar este problema. Tenga en cuenta que puede pasar matrices de diferentes tamaños a esta función:

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

5

El comportamiento que encontró es en realidad una gran verruga en el lenguaje C. Siempre que declara una función que toma un parámetro de matriz, el compilador lo ignora y cambia el parámetro a un puntero. Entonces todas estas declaraciones se comportan como la primera:

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

a será un puntero a int en los cuatro casos. Si pasa una matriz a func, inmediatamente se convertirá en un puntero a su primer elemento. (En un sistema de 64 bits, un puntero de 64 bits es dos veces más grande que un int de 32 bits, por lo que su tamaño de relación devuelve 2.)

El único propósito de esta regla es mantener la compatibilidad con versiones anteriores de los compiladores históricos que no admitían el paso de valores agregados como argumentos de función.

Esto no significa que sea imposible pasar una matriz a una función. Puede evitar esta verruga incrustando la matriz en una estructura (este es básicamente el propósito de std :: matriz de 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 pasando un puntero a la matriz:

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

En caso de que el tamaño de la matriz no sea una constante en tiempo de compilación, puede usar la técnica de puntero a matriz con matrices de longitud variable C99:

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

4

En c ++ puede pasar una matriz por referencia para este mismo propósito:

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

1
¿Cómo ayudaría esto con una pregunta C?
alq

3

En el lenguaje C, no existe un método para determinar el tamaño de una matriz desconocida, por lo que se debe pasar la cantidad, así como un puntero al primer elemento.


2
En general, siempre debe pasar el tamaño (número de elementos) de una matriz junto con una matriz a una función, a menos que tenga otros medios para determinar su tamaño (por ejemplo, un terminador de carácter nulo al final de char[]las matrices de cadenas).
David R Tribble

¿Qué es una " matriz desconocida "?
alq

3

No puede pasar matrices a funciones.

Si realmente desea imprimir el tamaño, puede pasar un puntero a una matriz, pero no será genérico en absoluto, ya que también debe definir el tamaño de la matriz para la función.

#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

El comportamiento es por diseño.

La misma sintaxis en la declaración de parámetros de función significa algo completamente diferente que en la definición de variable local.

La razón se describe en otras respuestas.


0

En lenguaje C, cuando pasa la matriz como argumento a la función, se convierte automáticamente en puntero, la matriz que pasa de una función a otra función se conoce como llamada por referencia. Esa es la razón por la que la función llamada solo recibe el puntero que apunta al primer elemento de la función Esta es la razón

fun (int a []) es similar a fun (int * a);

así que cuando imprima el tamaño de la matriz, imprimirá el tamaño del primer elemento.


En C no hay " llamada por referencia ".
alq

" cuando imprime el tamaño de la matriz, imprime el tamaño del primer elemento " . No, imprime el tamaño de un puntero.
alq

-1

En el lenguaje de programación 'C', 'sizeof ()' es el operador y devuelve el tamaño del objeto en bytes. El argumento del operador 'sizeof ()' debe ser un tipo de valor izquierdo (entero, número flotante, estructura, matriz Así que si quieres saber el tamaño de una matriz en bytes, puedes hacerlo de manera muy simple, solo usa el operador 'sizeof ()' y para su argumento usa el nombre de la matriz, por ejemplo:

#include <stdio.h>

main(){

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

}

La salida en el sistema de 32 bits será: El tamaño de n es: 40.Porque unteger en el sistema de 32 es 4bytes.En 64x es 8bytes.En este caso tenemos 10 enteros declarados en una matriz.Entonces el resultado es '10 * tamaño de ( En t)'.

Algunos consejos:

Si tenemos una matriz declarada como esta 'int n [] = {1, 2, 3, ... 155 ..};'. Entonces queremos saber cuántos elementos se almacenan en esta matriz. Utilice este algoritmo:

sizeof (nombre_del_arreglo) / sizeof (tipo_arreglo)

Código: #include

principal(){

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

}


2
Bienvenido a StackOverflow y gracias por escribir una respuesta. Desafortunadamente, esto no aborda la pregunta, que se trata específicamente de la diferencia entre sizeof(n)para una variable local y sizeof(arg)un argumento para una función, aunque ambos son aparentemente de tipo int[10].
MicroVirus

-3

Las matrices solo tienen un tamaño reducido. En su mayor parte, una matriz es un puntero a la memoria. El tamaño en su declaración solo le dice al compilador la cantidad de memoria que debe asignar para la matriz; no está asociado con el tipo, por lo que sizeof () no tiene nada que seguir.


3
Lo siento, esta respuesta es engañosa. Tampoco son las matrices "de tamaño flexible", ni son "punteros a la memoria". Las matrices tienen un tamaño muy exacto, y los lugares donde el nombre de una matriz representa un puntero a su primer elemento está especificado con precisión por el estándar C.
Jens
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.