Compartir en Twitter
Go to Homepage

CÓMO CALCULAR EL TAMAÑO DE UN ARRAY EN C CON SIZEOF EN 2025

November 2, 2025

Introducción al cálculo del tamaño de arrays en C

En el desarrollo de software de bajo nivel, especialmente en sistemas operativos, controladores de dispositivos y aplicaciones embebidas, el manejo preciso de la memoria es fundamental. Una de las operaciones más comunes es determinar cuántos elementos contiene un array declarado localmente. Aunque el lenguaje C no ofrece una función directa para obtener esta información, el operador sizeof proporciona una solución elegante y eficiente cuando se aplica correctamente. Este tutorial explora en profundidad cómo utilizar este operador para calcular el tamaño de un array, con énfasis en su comportamiento real, limitaciones prácticas y aplicaciones en código moderno.

El operador sizeof es una herramienta compile-time que devuelve el tamaño en bytes de cualquier tipo de dato o expresión. Cuando se aplica a un array, retorna el espacio total reservado en la pila para todos sus elementos. Este comportamiento permite, mediante una simple división, obtener el número de elementos. Sin embargo, este método solo funciona bajo ciertas condiciones específicas que deben comprenderse completamente para evitar errores sutiles en producción.

¿Qué es un array en el lenguaje C?

Un array es una estructura de datos estática que almacena múltiples valores del mismo tipo en ubicaciones contiguas de memoria. La declaración de un array requiere especificar su tipo base y, opcionalmente, su dimensión. Por ejemplo:

int numeros[10];

Esta línea reserva espacio para 10 enteros consecutivos. Alternativamente, se puede inicializar el array durante la declaración:

int numeros[] = {1, 2, 3, 4, 5};

En este caso, el compilador deduce automáticamente que el array tiene tamaño 5. Es importante destacar que, una vez declarado, el tamaño del array no puede modificarse. Esta característica lo diferencia de estructuras dinámicas como las listas enlazadas o los vectores de C++.

Los arrays en C mantienen una relación directa con los punteros: el nombre del array decae a un puntero al primer elemento en la mayoría de contextos. Esta propiedad, aunque poderosa, introduce complejidades al intentar calcular el tamaño del array fuera de su ámbito de declaración.

El operador sizeof y su funcionamiento interno

El operador sizeof es evaluado en tiempo de compilación y retorna un valor de tipo size_t, que es un tipo entero sin signo definido en <stddef.h>. Su sintaxis general es:

sizeof(expresión)

Cuando se aplica a un array declarado localmente, sizeof(array) devuelve el tamaño total en bytes del bloque de memoria asignado. Por ejemplo:

#include <stdio.h>

int main() {
    int datos[] = {10, 20, 30, 40, 50};
    printf("Tamaño total: %zu bytes\n", sizeof(datos));
    return 0;
}
Tamaño total: 20 bytes

En sistemas donde int ocupa 4 bytes, 5 elementos requieren 20 bytes. Este cálculo es exacto y determinista en tiempo de compilación.

Cálculo del número de elementos usando sizeof

Para obtener el número de elementos, se divide el tamaño total del array entre el tamaño de un solo elemento. La forma más común y segura es:

size_t longitud = sizeof(array) / sizeof(array[0]);

Este enfoque utiliza el primer elemento del array para determinar el tamaño del tipo base, garantizando compatibilidad incluso si el tipo cambia. Veamos un ejemplo completo:

#include <stdio.h>

int main() {
    char texto[] = "Programación";
    size_t longitud = sizeof(texto) / sizeof(texto[0]);

    printf("El array tiene %zu elementos\n", longitud);
    return 0;
}
El array tiene 13 elementos

El string literal “Programación” incluye el carácter nulo terminador \0, por lo que el array resultante tiene 13 elementos: 12 caracteres visibles más el terminador.

Aplicación práctica: búsqueda lineal en arrays

Una aplicación común del cálculo de tamaño es recorrer todos los elementos de un array. Consideremos una función que verifica si un valor está presente:

#include <stdio.h>
#include <stdbool.h>

bool contiene_valor(int arr[], size_t tam, int valor) {
    for (size_t i = 0; i < tam; i++) {
        if (arr[i] == valor) {
            return true;
        }
    }
    return false;
}

int main() {
    int primos[] = {2, 3, 5, 7, 11, 13, 17};
    size_t tam = sizeof(primos) / sizeof(primos[0]);

    int busqueda = 7;
    if (contiene_valor(primos, tam, busqueda)) {
        printf("El valor %d está en el array\n", busqueda);
    }

    return 0;
}
El valor 7 está en el array

Aquí, el cálculo del tamaño se realiza en main, donde el array aún conserva su información de dimensión.

Limitaciones críticas del método sizeof

El principal límite del operador sizeof surge cuando un array se pasa como parámetro a una función. En este contexto, el array decae a un puntero, perdiendo toda información sobre su tamaño. El compilador trata arr[] como int*, y sizeof(arr) devuelve el tamaño del puntero, no del array completo.

#include <stdio.h>

void funcion_mal(int arr[]) {
    // ¡Error! Esto NO da el tamaño del array
    size_t tam = sizeof(arr) / sizeof(arr[0]);
    printf("Tamaño percibido: %zu\n", tam);
}

int main() {
    int valores[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    funcion_mal(valores);
    return 0;
}
Tamaño percibido: 1 (o 2 en sistemas de 64 bits)

En sistemas de 64 bits, un puntero ocupa 8 bytes, por lo que sizeof(arr) es 8 y sizeof(arr[0]) es 4, dando como resultado 2. Este error es común y peligroso.

Soluciones robustas para arrays como parámetros

Para superar esta limitación, se deben implementar patrones de diseño específicos:

Paso explícito del tamaño

#include <stdio.h>

void procesar_array(int arr[], size_t tam) {
    printf("Procesando %zu elementos:\n", tam);
    for (size_t i = 0; i < tam; i++) {
        printf("Elemento %zu: %d\n", i, arr[i]);
    }
}

int main() {
    int datos[] = {100, 200, 300, 400};
    size_t tam = sizeof(datos) / sizeof(datos[0]);
    procesar_array(datos, tam);
    return 0;
}

Uso de macros para arrays locales

Cuando se trabaja exclusivamente con arrays locales, una macro puede encapsular el cálculo:

#define TAMANO_ARRAY(arr) (sizeof(arr) / sizeof((arr)[0]))

#include <stdio.h>

int main() {
    double reales[] = {3.14, 2.71, 1.41, 1.73};
    size_t n = TAMANO_ARRAY(reales);

    printf("El array tiene %zu elementos de tipo double\n", n);
    return 0;
}

Esta macro es type-safe y funciona correctamente solo dentro del ámbito donde el array fue declarado.

Consideraciones de portabilidad y tipos de datos

El tamaño de los tipos fundamentales varía entre arquitecturas. En sistemas embebidos de 8 bits, int puede ser de 16 bits, mientras que en sistemas de 64 bits modernos suele ser de 32 bits. El uso de sizeof(array[0]) en lugar de sizeof(int) asegura que el cálculo sea correcto independientemente del tamaño real del tipo.

#include <stdio.h>

int main() {
    long long grandes[] = {1000000LL, 2000000LL, 3000000LL};
    size_t tam = sizeof(grandes) / sizeof(grandes[0]);

    printf("Cada elemento ocupa %zu bytes\n", sizeof(grandes[0]));
    printf("Total de elementos: %zu\n", tam);
    return 0;
}
Cada elemento ocupa 8 bytes
Total de elementos: 3

Arrays multidimensionales y sizeof

El operador sizeof también funciona con arrays de múltiples dimensiones. Consideremos una matriz 3x4:

#include <stdio.h>

int main() {
    int matriz[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    };

    size_t filas = sizeof(matriz) / sizeof(matriz[0]);
    size_t columnas = sizeof(matriz[0]) / sizeof(matriz[0][0]);

    printf("Matriz de %zu x %zu\n", filas, columnas);
    return 0;
}
Matriz de 3 x 4

Este patrón se extiende a cualquier número de dimensiones, siempre que se aplique sizeof en el ámbito correcto.

Buenas prácticas en código moderno (2025)

En proyectos actuales, especialmente en sistemas críticos, se recomienda:

  • Usar size_t para índices y tamaños
  • Validar que los arrays no estén vacíos antes de divisiones
  • Documentar claramente cuándo un parámetro es un puntero decadido
  • Preferir estructuras que incluyan su propio contador cuando sea posible
typedef struct {
    size_t capacidad;
    size_t usados;
    int *datos;
} VectorDinamico;

Aunque esta estructura supera las limitaciones de los arrays estáticos, comprender sizeof sigue siendo esencial para interoperabilidad con APIs legacy y optimización de rendimiento.

Arrays de estructuras y alineamiento

Cuando los arrays contienen estructuras, el padding y el alineamiento pueden afectar el tamaño total. Sin embargo, sizeof siempre refleja el layout real en memoria:

#include <stdio.h>

typedef struct {
    char flag;
    int valor;
} Paquete;

int main() {
    Paquete paquetes[2] = {{1, 100}, {0, 200}};
    size_t tam = sizeof(paquetes) / sizeof(paquetes[0]);

    printf("Cada paquete ocupa %zu bytes (incluyendo padding)\n", sizeof(paquetes[0]));
    printf("Total de paquetes: %zu\n", tam);
    return 0;
}

En la mayoría de sistemas, Paquete ocupará 8 bytes debido al alineamiento del int a 4 bytes.

Depuración y verificación del tamaño

Durante el desarrollo, es útil verificar que los cálculos sean correctos:

#include <stdio.h>
#include <assert.h>

int main() {
    float muestras[100];
    size_t calculado = sizeof(muestras) / sizeof(muestras[0]);

    assert(calculado == 100 && "Error en cálculo de tamaño");
    printf("Cálculo correcto: %zu elementos\n", calculado);
    return 0;
}

El uso de assert en modo debug ayuda a detectar errores temprano.

Comparación con alternativas en otros lenguajes

Aunque C requiere este cálculo manual, lenguajes como C++ ofrecen std::size() para contenedores, y Rust usa .len() en slices. En C, la combinación de sizeof con macros sigue siendo la solución estándar y más eficiente, especialmente en entornos donde no se permite la biblioteca estándar completa.

Errores comunes y cómo evitarlos

  1. Usar sizeof en parámetros de función: siempre pasar el tamaño explícitamente
  2. Asumir tamaños fijos de tipos: usar sizeof(elemento) garantiza portabilidad
  3. Olvidar el terminador nulo en strings: sizeof lo incluye automáticamente
  4. Aplicar sizeof a punteros dinámicos: malloc no preserva información de tamaño

Optimización en sistemas embebidos

En microcontroladores con memoria limitada, conocer el tamaño exacto de los buffers es crítico. El uso de sizeof permite al compilador verificar en tiempo de compilación que los arrays no excedan la RAM disponible:

#include <stdio.h>

uint8_t buffer[64];  // Buffer para comunicación serial

static_assert(sizeof(buffer) <= 64, "Buffer excede límite de RAM");

Aunque static_assert requiere C11, su uso previene errores de desbordamiento en firmware.

Conclusiones

El operador sizeof representa una de las herramientas más poderosas y subestimadas del lenguaje C para el manejo de arrays. Cuando se aplica correctamente dentro del ámbito de declaración del array, proporciona un método exacto y eficiente para determinar su longitud sin costo en tiempo de ejecución. Sin embargo, su uso requiere comprensión profunda de las reglas de decaimiento de arrays y las diferencias entre compilación y ejecución.

En la práctica moderna de 2025, dominar sizeof sigue siendo esencial para escribir código robusto, portable y eficiente, especialmente en sistemas embebidos, controladores y aplicaciones de alto rendimiento. La combinación de este operador con macros, paso explícito de parámetros y validaciones en tiempo de compilación forma la base de las mejores prácticas en programación de sistemas en C.

La clave del éxito radica en recordar que sizeof opera en tiempo de compilación y solo conserva información completa sobre arrays estáticos locales. Con esta comprensión, los desarrolladores pueden evitar errores comunes y escribir código que sea simultáneamente correcto, eficiente y mantenible a largo plazo.




  • Descubre en este tutorial exhaustivo todo sobre las sentencias if en C: desde la sintaxis básica hasta estructuras complejas como if-else y anidaciones. Incluye ejemplos prácticos, mejores prácticas y errores comunes para dominar el control de flujo en programación C, ideal para desarrolladores principiantes y avanzados en 2025.