DMarlon Studio

Lección 2 · 2 de 20

Memoria dinámica: malloc, calloc y free · C

Reserve memoria en tiempo de ejecución en C con malloc y calloc, compruebe NULL y libérela con free: las notas de una clase y su histograma.

C · Memoria dinámica: malloc, calloc y free en DMarlon Studio: el código del ejemplo y su salida en la terminal

Un array normal tiene un tamaño fijo al compilar. Cuando el tamaño se conoce solo al ejecutar (cuántos alumnos hay en un archivo, por ejemplo), se pide la memoria al montón (*heap*) con `malloc`, que recibe un número de bytes y devuelve un puntero al bloque.

malloc(students * sizeof *marks) pide sitio para 10 int. Escribir sizeof *marks en vez de sizeof(int) hace que el cálculo siga siendo correcto si un día cambia el tipo del puntero. Si no hay memoria, malloc devuelve NULL, y hay que comprobarlo antes de usar el bloque.

Lo que devuelve malloc no está inicializado: contiene lo que hubiera antes. Por eso el bucle escribe cada nota antes de leerla. **calloc(11, sizeof *count)** reserva 11 contadores y además los pone a cero, justo lo que hace falta para contar cuántas veces sale cada nota con count[marks[i]]++.

Cada bloque reservado se devuelve con `free` exactamente una vez. Si falla el segundo calloc, el programa libera primero marks antes de salir. Después de free, el puntero sigue guardando la dirección antigua (un puntero colgante); ponerlo a NULL evita usarlo por error.

Olvidar un free es una fuga de memoria: en un programa corto no se nota, pero en un servidor que funciona días acaba agotando la memoria.

Código · main.c

#include <stdio.h>#include <stdlib.h>int main(void) {    int students = 10;  // known only at run time in a real program    // malloc: room for 10 ints. Its contents are garbage until we write them.    int *marks = malloc(students * sizeof *marks);    if (marks == NULL) {        fprintf(stderr, "Out of memory\n");        return 1;    }    for (int i = 0; i < students; i++)        marks[i] = (i * 7 + 3) % 6 + 5;  // marks from 5 to 10    // calloc: room for 11 counters, all set to zero. Ideal for counting.    int *count = calloc(11, sizeof *count);    if (count == NULL) { free(marks); return 1; }    for (int i = 0; i < students; i++) count[marks[i]]++;    printf("Marks:");    for (int i = 0; i < students; i++) printf(" %d", marks[i]);    printf("\n");    for (int m = 5; m <= 10; m++) {        printf("%2d | ", m);        for (int k = 0; k < count[m]; k++) printf("*");        printf(" %d\n", count[m]);    }    free(count);  // every malloc or calloc needs exactly one free    free(marks);    marks = NULL;  // a freed pointer must not be used again    return 0;}

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

Marks: 8 9 10 5 6 7 8 9 10 5
 5 | ** 2
 6 | * 1
 7 | * 1
 8 | ** 2
 9 | ** 2
10 | ** 2

Para recordar

  • malloc(n * sizeof *p) reserva sin inicializar.
  • calloc(n, sizeof *p) reserva y pone todo a cero.
  • Compruebe siempre si devuelven NULL.
  • Un free por cada reserva, y no use el puntero después.

Ejercicio

Cambie el programa para que también calcule la media: reserve con malloc un array de double con la nota de cada alumno sobre 100 (nota × 10), escríbalo y libérelo al final.