DMarlon Studio

Lesson 2 · 2 of 20

Dynamic memory: malloc, calloc, free · C

Allocate memory at run time in C with malloc and calloc, check for NULL and release it with free: a class's marks and their histogram.

C · Dynamic memory: malloc, calloc, free in DMarlon Studio: the example's code and its output in the terminal

A regular array has a fixed size at compile time. When the size is only known while running (how many students are in a file, say), you ask the heap for memory with `malloc`, which takes a number of bytes and returns a pointer to the block.

malloc(students * sizeof *marks) asks for room for 10 ints. Writing sizeof *marks instead of sizeof(int) keeps the size right if the pointer's type ever changes. When memory runs out, malloc returns NULL, and you must check that before using the block.

What malloc returns is not initialised: it holds whatever was there before. That is why the loop writes every mark before reading it. **calloc(11, sizeof *count)** reserves 11 counters and also sets them to zero, exactly what is needed to count each mark with count[marks[i]]++.

Every block you allocate goes back with `free` exactly once. If the second calloc fails, the program frees marks before leaving. After free, the pointer still holds the old address (a dangling pointer); setting it to NULL stops you from using it by mistake.

Forgetting a free is a memory leak: invisible in a short program, but a server that runs for days eventually runs out of memory.

Code · 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;}

Output · 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

Key points

  • malloc(n * sizeof *p) allocates without initialising.
  • calloc(n, sizeof *p) allocates and zeroes everything.
  • Always check whether they return NULL.
  • One free per allocation, and do not use the pointer afterwards.

Exercise

Make the program also work out the average: allocate with malloc an array of double with each student's mark out of 100 (mark × 10), print it and free it at the end.