2011-05-09 18 views
8

Estoy estudiando para una final mañana en C, y tengo una pregunta sobre el tamaño del operador.sizeof array clarification

Digamos que el tamaño de int es bits y un puntero es 64 bits.

Si hubiera una función:

int 
foo (int zap[]) 
{ 
    int a = sizeof(zap); 
    return a; 
} 

Debido zap es un puntero, foo regresarían 8, ya que así es como se necesitan muchos bytes para almacenar este puntero particular. Sin embargo, con el siguiente código:

int zip[] = { 0, 1, 2, 3, 4, 5 }; 
int i = sizeof(zip); 

i habría 6 * sizeof(int) = 6 * 4 = 24

Por qué es que sizeof(zip) devuelve el número de elementos de veces el tamaño de cada elemento, mientras que sizeof(zap) devuelve el tamaño de una ¿puntero? ¿Es que el tamaño de zap no está especificado y zip no? El compilador sabe que zip es 6 elementos, pero no tiene ni idea de cuán grande puede ser zap.

Respuesta

8

Esto es una especie de asimetría en la sintaxis C. En C no es posible pasar una matriz a una función, de modo que cuando se usa la sintaxis de la matriz en una declaración de función para uno de los parámetros, el compilador la lee como un puntero.

En C, en la mayoría de los casos, cuando utiliza una matriz en una expresión, la matriz se convierte implícitamente en un puntero a su primer elemento y eso es exactamente lo que ocurre cuando se llama a una función. En el siguiente código:

int bar[] = {1,2,3,4}; 
foo(bar); 

la matriz se convierte en un puntero al primer elemento y que es lo que recibe la función.

Esta regla de conversión implícita no siempre se aplica. Como descubrió, por ejemplo, el operador sizeof trabaja en la matriz, e incluso el operador & (dirección de) trabaja en la matriz original (es decir, sizeof(*&bar) == 4*sizeof(int)).

Una función en C no puede recibir una matriz como parámetro, solo puede recibir un puntero al primer elemento o un puntero a una matriz ... o debe envolver la matriz en una estructura.

Incluso si se pone un número entre los paréntesis de la declaración de la función ...

void foo(int x[4]) 
{ 
    ... 
} 

ese número es completamente ignorado por el compilador ... que la declaración para el compilador es totalmente equivalente a

void foo(int *x) 
{ 
    ... 
} 

y, por ejemplo, incluso llamándolo el paso de una matriz con un tamaño diferente, no dará lugar a ningún error ...

int tooshort[] = {1,2,3}; 
foo(tooshort); /* Legal, even if probably wrong */ 

(en realidad un compilador PUEDE dar una advertencia, pero el código es C perfectamente legal y debe ser aceptada si el compilador sigue el estándar)

Si usted piensa que esta regla acerca de las matrices, cuando en argumentos de la función es extraña entonces estoy de acuerdo, pero así es como se define el lenguaje C.

+0

El compilador no ignora el número, int x [4] como parámetro de función significa que debe pasar un puntero de matriz de _exactly_ 4 elementos. Es lo mismo que escribir 'int (* x) [4]' en otro lugar del código. Aparte de eso, esta respuesta señala el problema: la sintaxis de matriz para los parámetros tiene un significado diferente para las matrices declaradas en otras partes del programa. Es una de las "características" más tontas del lenguaje C. Para evitar confusiones, use siempre la notación 'int * x' para los parámetros. – Lundin

+0

¿Puede indicar dónde está escrito en el estándar que el número entre paréntesis debe ser igual al tamaño de la matriz pasada? Sugerencia: este sería un requerimiento extraño dado que no se puede pasar una matriz y que la función en realidad solo recibe un puntero. Cuando se llama a una función con 'foo (bar)' donde 'bar' es una matriz, esa matriz ya se ha convertido en un puntero ** incluso para el compilador ** antes de considerar la llamada a la función. No tendría sentido imponer una limitación a la información de tamaño que ya se ha descartado en la conversión. – 6502

+0

@Lundin, no para la primera dimensión de los parámetros de matriz, el 4 es esencialmente ignorado. C99 tiene la posibilidad de la palabra clave 'static' además, allí, para especificar que la función espera * al menos * para los elementos. Pero aún así, el tipo del parámetro es 'int *'. –

2

Porque zip es array y el compilador conoce su tamaño en tiempo de compilación. Es sólo un caso de uso de la misma notación para dos cosas diferentes, algo bastante habitual en C.

int 
foo (int zap[]) 

es completamente equivalente a

int 
foo (int *zap) 

El compilador no tiene ni idea de lo grande que podía zap ser (por lo que deja la tarea de averiguar al programador).

+1

La faq C en esto es ** invaluable **: http://c-faq.com/aryptr/index.html – cnicutar

+0

Incluso si pones un número entre los corchetes, sin embargo, eso sigue siendo solo un puntero y el número sí mismo es completamente ignorado por el compilador. Entonces, no es un problema que el compilador no conozca el tamaño ... es que el lenguaje C tiene una regla extraña especial sobre las matrices en las listas de argumentos de funciones. – 6502

+0

@ 6502 Estás en lo cierto, es una buena idea. Poner un número entre corchetes tendrá el mismo efecto, por lo que se desaconseja rotundamente. – cnicutar

-1

porque se ha inicializado estáticamente con 6 elemens.

+0

alguien quiere aclarar downvote? Mi respuesta es la misma que las otras 2, ¿solo un poco más sucinta? –

+0

No he utilizado el voto a la baja, pero realmente no importa si se "inicializó" o no "zip". El problema radica en la sintaxis del parámetro de función extraño de C. – Lundin

0

El tamaño de zip es conocido en tiempo de compilación y el tamaño de zap no lo es. Es por eso que obtiene el tamaño de un puntero en sizeof(zap) y el tamaño de la matriz en sizeof(zip).

2

es un bloque de memoria de 6 * sizeof(int) por lo que tiene un tamaño de 24 (en su arquitectura). zap (también podría escribirse como int *zap en su declaración de función), pero puede señalar cualquier dirección de memoria y el compilador no tiene forma de saber cuánto espacio se ha asignado a partir de esta dirección (o incluso que contiene esta).

0

Hay algunas situaciones en las que las copias se degradan en los punteros. Llamadas de función es una de esas.