Arrays en C: declaración, inicialización y acceso

Un array es, esencialmente, una secuencia contigua de elementos del mismo tipo almacenados en un bloque de memoria continuo. Imagina una estantería de almacén donde cada compartimento tiene exactamente el mismo tamaño: si sabes dónde empieza la primera caja, puedes calcular la posición de cualquier otra simplemente contando cuántos espacios hay de diferencia. En C, un array no es un objeto complejo, sino una dirección de memoria base más un desplazamiento.

Esta estructura permite que el acceso a cualquier elemento sea extremadamente rápido (tiempo constante), ya que el compilador calcula la dirección de memoria necesaria mediante una operación aritmética simple: dirección_base + (índice * tamaño_del_tipo). Debido a que el primer elemento está en la dirección base, su desplazamiento es cero, y por eso los arrays en C siempre comienzan con el índice 0. Usaríamos arrays cuando necesitamos almacenar colecciones de datos de un mismo tipo (como una lista de temperaturas o una matriz de píxeles) y queremos la máxima eficiencia de acceso. Sin embargo, si te equivocas calculando el índice o el tamaño, el programa intentará leer o escribir en una zona de memoria que no le pertenece, lo que resulta en Comportamiento Indefinido (Undefined Behavior): el programa podría cerrarse repentinamente (segmentation fault), corromper otras variables o, lo que es peor, seguir funcionando con datos basura sin avisarte del error.

#include <stdio.h>

int main(void) {
    // Declaración con tamaño inferido por el compilador
    int valores[] = {10, 20, 30, 40, 50};

    // Para saber cuántos elementos hay, dividimos el tamaño total en bytes
    // por el tamaño de un solo elemento.
    size_t cantidad = sizeof(valores) / sizeof(valores[0]);

    // Inicialización parcial: los elementos no declarados se inicializan a 0.
    int estados[5] = {1, 3}; // El resto (índices 2, 3 y 4) serán 0.

    // Inicialización mediante designadores [C99]: permite asignar valores
    // a índices específicos de forma clara.
    int mapa[10] = { [0] = 100, [5] = 500, [9] = 999 };

    // Arrays multidimensionales: se almacenan en orden de fila (row-major).
    // Esto significa que todos los elementos de la primera fila van seguidos
    // de los elementos de la segunda fila en la memoria física.
    int matriz[2][3] = {
        {1, 2, 3},
        {4, 5, 6}
    };

    printf("--- Array 'valores' ---\n");
    for (size_t i = 0; i < cantidad; i++) {
        printf("Elemento [%zu]: %d\n", i, valores[i]);
    }

    printf("\n--- Array 'mapa' (indices 0, 5, 9) ---\n");
    printf("Indice 0: %d, Indice 5: %d, Indice 9: %d\n", mapa[0], mapa[5], mapa[9]);

    printf("\n--- Matriz 2x3 (Acceso fila/columna) ---\n");
    for (int f = 0; f < 2; f++) {
        for (int c = 0; c < 3; c++) {
            // El compilador calcula la posición real internamente
            printf("%d ", matriz[f][c]);
        }
        printf("\n");
    }

    return 0;
}

Análisis del código

En el ejemplo, la variable valores se define sin un tamaño explícito entre los corchetes []. El compilador cuenta cuántos enteros hay en la lista de inicialización y reserva el espacio necesario. Para obtener este número, no podemos usar sizeof(valores) directamente para saber cuántos elementos hay, ya que sizeof nos devuelve el tamaño total en bytes (en este caso, 5 * sizeof(int)). Al dividirlo por sizeof(valores[0]), obtenemos la cantidad de elementos de forma portable.

Cuando inicializamos estados, aprovechamos que C rellena con ceros cualquier posición no mencionada explícitamente. Esto es una práctica común para asegurar que un array esté “limpio”. Por otro lado, la inicialización de mapa utiliza la sintaxis [índice] = valor [C99], que es extremadamente útil cuando solo necesitas modificar elementos dispersos en un array muy grande.

En la matriz matriz[2][3], la estructura es lógica para nosotros (filas y columnas), pero para la CPU es una línea continua. Para acceder a matriz[1][0] (el primer elemento de la segunda fila), el sistema calcula la posición saltándose la primera fila completa. Esta disposición se llama row-major order y es el estándar en C.

El error frecuente

Uno de los errores más peligrosos en C es el acceso fuera de los límites (out-of-bounds). Fíjate en este fragmento:

int datos[5] = {10, 20, 30, 40, 50};
int valor = datos[5]; // ¡ERROR!

El array datos tiene 5 elementos, lo que significa que sus índices válidos son 0, 1, 2, 3 y 4. Al pedir el índice 5, estás intentando acceder a la memoria que está inmediatamente después del último elemento. En un programa pequeño, esto podría parecer que funciona y devuelva un valor aleatorio de la pila, pero en producción esto puede sobrescribir una variable crítica o causar un fallo de segmentación. Herramientas como AddressSanitizer (usando -fsanitize=address en gcc) son esenciales para detectar estos desbordamientos durante el desarrollo.

52

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll al inicio