En el lenguaje C, los arreglos son la estructura básica para almacenar un conjunto ordenado de elementos del mismo tipo. Proporcionan un acceso rápido por índice y están estrechamente relacionados con el funcionamiento de los punteros. Los arreglos pueden ser declarados de forma estática, automática (en la pila) o dinámica (en el montón). El tipo de asignación afecta la duración del arreglo, su disponibilidad desde diferentes partes del código y los requerimientos de gestión de memoria.
Historia del tema
El C original permitía definir solo arreglos estáticos y automáticos, pero con la aparición de la asignación dinámica de memoria (funciones malloc, calloc, free), surgieron nuevos patrones de diseño que aumentaron la flexibilidad del código.
Problema
Los desarrolladores frecuentemente cometen errores con los tamaños, la duración y la limpieza de los arreglos, lo que lleva a fugas, condiciones de carrera y daños en la memoria.
Solución
La selección cuidadosa del tipo de almacenamiento en función de la tarea, el seguimiento cuidadoso de la inicialización y la liberación oportuna de memoria para los arreglos dinámicos.
Ejemplo de código:
#include <stdio.h> #include <stdlib.h> int main() { // Automático (en la pila) int auto_arr[5] = {1,2,3,4,5}; // Estático (vive mientras la programa funciona) static int static_arr[5]; // Dinámico (en el montón) int *dyn_arr = malloc(5 * sizeof(int)); for (int i = 0; i < 5; i++) dyn_arr[i] = i * 2; // Uso for (int i = 0; i < 5; i++) printf("%d ", dyn_arr[i]); printf(" "); free(dyn_arr); return 0; }
Características clave:
¿Se puede conocer el tamaño de un arreglo dinámico a través de sizeof?
No, sizeof(ptr) para un arreglo dinámico devolverá el tamaño del puntero, no del arreglo. Es necesario almacenar manualmente el tamaño o usar una variable separada.
int* arr = malloc(10 * sizeof(int)); printf("%zu ", sizeof(arr)); // Tamaño del puntero, no del arreglo
¿Qué sucede al salir de los límites del arreglo?
En el lenguaje C no hay verificación automática de los límites del arreglo: el acceso fuera de los límites conduce a un comportamiento indefinido. Los errores se detectan solo en tiempo de ejecución o no se detectan en absoluto.
¿Se puede devolver un arreglo local (automático) desde una función?
¡No! Un arreglo declarado dentro de una función se elimina después de que esta finaliza. Devolver tal arreglo lleva a un acceso a memoria ya liberada.
int* create_wrong_array() { int arr[10]; return arr; // Error: devolver un puntero a la pila }
Un desarrollador crea un arreglo en la pila y devuelve un puntero a él desde la función. El programa a veces falla o devuelve basura.
Pros:
Contras:
Uso de asignación dinámica con paso de dimensiones junto con un puntero, limpieza de memoria a través de free. Todos los casos de liberación de memoria son verificados por pruebas unitarias.
Pros:
Contras: