Los punteros y los arreglos en C están relacionados, pero no son lo mismo:
Al pasar un arreglo a una función, de hecho se pasa un puntero al primer elemento del arreglo (por lo que sizeof dentro de la función no da el tamaño de todo el arreglo, sino solo el tamaño del puntero).
Sintaxis para pasar:
void foo(int arr[], int size) { // arr — de hecho int* for (int i = 0; i < size; ++i) printf("%d\n", arr[i]); } int main() { int data[5] = {1,2,3,4,5}; foo(data, 5); }
Pregunta: ¿Qué devolverá la expresión sizeof(arr) dentro de la función, si arr es un parámetro de tipo int arr[]?
Respuesta: Devuelve el tamaño del puntero (sizeof(int*)), y no el tamaño de todo el arreglo. Porque se pasa a la función un puntero al primer elemento, la información sobre la longitud se pierde.
void printSize(int arr[]) { printf("%zu\n", sizeof(arr)); // sizeof(int*) generalmente 4 u 8 }
Historia
En un proyecto comercial se escribió un código para calcular el promedio de un arreglo, donde se tomaba sizeof(arr) / sizeof(arr[0]) para el número de elementos dentro de la función, lo que siempre devolvía 1 o 2 en lugar de la verdadera cantidad de elementos. Debido a esto, el programa funcionaba incorrectamente con los datos, promediando valores incorrectamente.
Historia
En un proyecto, un arreglo dinámicamente asignado se pasó a una función sin almacenar por separado la longitud (size). Como resultado, la función no sabía cuántos elementos se habían asignado, lo que llevaba a desbordamientos, pérdidas o corrupción de memoria.
Historia
Por error, se utilizó un arreglo de tamaño fijo como puntero, y en algunos compiladores se permitía la asignación directa a través de memcpy de todo el arreglo en lugar de sus elementos. Esto llevó a errores no evidentes, donde se perdían partes de la estructura de datos o ocurría un desbordamiento de pila.