2012-07-23 17 views
10

Quiero obtener la longitud de una matriz, digamos int array[] = {1, 2, 3, 4}. Usé sizeof para hacer eso.¿Por qué sizeof (param_array) es el tamaño del puntero?

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 
} 

Así que, ¿por qué la sizeof(array) en función length devuelve el tamaño del puntero de array? Pero en la función main, funciona.

Y, ¿cómo debo modificar la función length para obtener la longitud de una matriz?

+1

Sí, sé que esto es una cuestión de C++, pero contiene información muy útil respecto a C, así: http://stackoverflow.com/questions/4810664/how-do-i-use-arrays-in -c – chris

Respuesta

18

Una regla C especial dice que para los parámetros de función, los tipos de matriz son ajustados a tipos de puntero.Eso significa:

int length(int array[]);

es equivalente a

int length(int *array);

Así que cuando se calcule el sizeof la matriz en realidad se está calculando el tamaño del puntero.

(C99, 6.7.5.3p7) "Una declaración de un parámetro como 'matriz de tipo' se ajusta a 'puntero calificado para escribir', donde los calificadores de tipo (si los hay) son los especificados dentro de el [y] de la derivación del tipo de matriz ".

+4

... y la consecuencia de esto es que no puede volver a escribir 'length()' para que funcione como desee; si una función necesita saber el tamaño de una matriz, debe pasarse a esa función como un parámetro separado. – caf

+0

@caf Estoy de acuerdo contigo. Para obtener información adicional, tiene sentido hacerlo de esta manera, especialmente cuando se utiliza un procesador ARM con registros r0, r1, r2, r3 de 32 bits. Por lo tanto, un puntero se puede pasar en r0 en lugar de tener que usar la pila. –

2

C no almacena metadatos en tiempo de ejecución sobre el tamaño de una matriz con la variable. Tendrás que guardarlo tú mismo en alguna parte.

una variable de tipo int [] en el contexto de la longitud de su método es sólo un puntero a un bloque de memoria. Es por eso que el tamaño es el mismo que el de cualquier otro puntero en su sistema.

Cuando sizeof tiene acceso a la matriz en tiempo de compilación (como en su función principal ) que en su lugar devolverá el número de bytes ocupados por la matriz.

+1

"Una variable de tipo int [] es solo un puntero a un bloque de memoria" - eso es incorrecto en el caso general. Una variable de tipo 'int []' * es * un bloque de memoria. No es un puntero. Los únicos contextos donde 'int []' representa un puntero es una declaración de parámetro de función y es un * caso especial *. – AnT

+0

Se aclaró que es un puntero * en el contexto de la longitud del método() *. Gracias por señalar eso. –

3

En el programa principal, el compilador conoce la longitud de la matriz. En la subrutina, no es así. En particular, en una subrutina, un parámetro del tipo int[] es idéntico a un parámetro del tipo int *. En el programa principal, por otro lado, array tiene tipo int[4]. (Puede probar esto al intentar asignar otro valor a array en el lado main. El compilador se quejará)

0

Porque la matriz variable dentro de la longitud no es la misma que la externa. Debe mantener el tamaño de (array)/sizeof (int) en la función principal.

4

La matriz se desintegra en un puntero cuando la pasa a una función.

0

Para modificar el código para que length puede obtener longitud de la matriz, lo convierten en una macro:

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

Para su ejemplo de código, este se comportará como se espera.

Tenga en cuenta que esto solo funciona en arreglos asignados estáticamente, y solo cuando se llama utilizando la matriz original (no funcionará cuando se utiliza un puntero a la matriz). Esto se debe a que cuando escribe sizeof(x) donde x es un puntero a una matriz, el compilador lo interpreta literalmente. No tiene ninguna forma de correlacionar x con la matriz a la que apunta antes de evaluar sizeof.

1

Si quiere que length tenga en cuenta el tamaño real de la red pasante, esa información debe pasarse, como todos dicen. Sin embargo, es posible que se reciba una referencia a la matriz con la información también incorporada:

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 
} 

no sé lo bueno que en realidad le hace, sin embargo, ya que el tamaño ya está prevista en el primer lugar. Pero verá que el operador sizeof funciona como lo desea en este caso.

4

Como han notado los otros contestadores, una función declarada para tomar una matriz se compila igual que si tomara un puntero.

La forma más común que he visto de hacer su método de longitud es con un #define, pero si juega trucos con las plantillas, puede hacer que su función funcione.

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 su gama de longitud 4, esto se compila como un método que toma una matriz de longitud 4, y devuelve una estática 4. Esto también tiene la ventaja de que si se intenta pasar algo que no es una matriz, el compilador dará un error, mientras que el método #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

Pregunta etiquetada C, no C++. – jxh

+0

Ah, está bien. Bueno, tal vez lo encuentre útil de todos modos. –

Cuestiones relacionadas