DMarlon Studio

Lección 3 · 3 de 20

realloc y un array que crece · C

Construya en C un array dinámico que crece con realloc, duplicando su capacidad, para guardar lecturas de un sensor sin saber cuántas llegarán.

C · realloc y un array que crece en DMarlon Studio: el código del ejemplo y su salida en la terminal

Muchas veces no se sabe cuántos datos van a llegar: las lecturas de un sensor, las líneas de un archivo. La solución es un array dinámico: el struct Readings guarda el puntero a los datos, cuántos se usan (len) y cuántos caben (cap).

push añade un valor. Si el array está lleno (len == cap), pide más sitio con `realloc`, que agranda el bloque o lo copia a otro mayor y devuelve la nueva dirección. La capacidad se duplica (2, 4, 8, 16): así hay pocas reservas aunque se añadan miles de valores.

El resultado de realloc se guarda primero en bigger, no directamente en r->data. Si realloc falla devuelve NULL pero el bloque antiguo sigue siendo válido; con r->data = realloc(r->data, …) se perdería la única dirección que lo libera.

temps empieza con NULL y capacidad 0: realloc(NULL, n) funciona como malloc(n), así que no hace falta un caso aparte para la primera reserva. Las líneas grow: de la salida muestran cada vez que el array ha crecido.

Al final basta un solo free(temps.data), porque todo está en un bloque. Si push falla, main libera lo que ya tenía antes de salir.

Código · main.c

#include <stdio.h>#include <stdlib.h>// A growing array: the data, how many are used and how many fit.typedef struct { double *data; size_t len, cap; } Readings;int push(Readings *r, double value) {    if (r->len == r->cap) {        size_t new_cap = r->cap ? r->cap * 2 : 2;        // realloc into a temporary: if it fails, the old block is still ours.        double *bigger = realloc(r->data, new_cap * sizeof *bigger);        if (bigger == NULL) return 0;        printf("  grow: %zu -> %zu\n", r->cap, new_cap);        r->data = bigger;        r->cap = new_cap;    }    r->data[r->len++] = value;    return 1;}int main(void) {    Readings temps = {NULL, 0, 0};  // realloc(NULL, n) works like malloc(n)    double sensor[] = {18.5, 19.0, 20.25, 21.0, 22.5, 21.75, 20.0, 19.5, 18.0};    for (size_t i = 0; i < sizeof sensor / sizeof sensor[0]; i++)        if (!push(&temps, sensor[i])) { free(temps.data); return 1; }    double sum = 0;    for (size_t i = 0; i < temps.len; i++) sum += temps.data[i];    printf("%zu readings, capacity %zu, average %.2f\n",           temps.len, temps.cap, sum / temps.len);    free(temps.data);    return 0;}

Salida · cc main.c -o main && ./main

  grow: 0 -> 2
  grow: 2 -> 4
  grow: 4 -> 8
  grow: 8 -> 16
9 readings, capacity 16, average 20.06

Para recordar

  • Un array dinámico guarda datos, longitud y capacidad.
  • Duplicar la capacidad evita llamar a realloc en cada valor.
  • Guarde el resultado de realloc en una variable temporal.
  • realloc(NULL, n) es lo mismo que malloc(n).

Ejercicio

Añada una función pop que quite y devuelva la última lectura y, cuando len baje a un cuarto de cap, reduzca la capacidad a la mitad con realloc.