LearnFrenzy
Sign in Take a free test

Dynamic Memory Allocation · Lesson 25 of 35

malloc, calloc and free in C

4 min read Updated Nov 7, 2026 Saurabh Samir

So far every array had a size fixed when you wrote the program. But often you only know the size at run time: how many students the user enters, how big a file is. Dynamic memory allocation lets you request exactly as much memory as you need from the heap while the program runs – and gives you the job of returning it.

In this lesson

  • Stack vs heap
  • malloc and checking for NULL
  • calloc and how it differs
  • free, and why every allocation needs one

Stack vs heap

StackHeap
Holdslocal variables, function callsmemory you request with malloc/calloc/realloc
Sizesmall (often 1–8 MB)large – most of the free RAM
Lifetimeends when the function returnsuntil you call free
Managed bythe compiler, automaticallyyou
Speedvery fastslower to allocate

malloc

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int n;
    printf("How many students? ");
    scanf("%d", &n);

    int *marks = malloc((size_t)n * sizeof *marks);    // room for n ints on the heap
    if (marks == NULL) {                                // allocation can fail
        printf("Out of memory\n");
        return 1;
    }

    int total = 0;
    for (int i = 0; i < n; i++) {
        marks[i] = 60 + i * 7;                          // use it like an array
        total += marks[i];
    }
    printf("Marks:");
    for (int i = 0; i < n; i++) printf(" %d", marks[i]);
    printf("\nAverage: %.2f\n", (double)total / n);

    free(marks);                                        // give the memory back
    marks = NULL;                                       // avoid a dangling pointer
    return 0;
}

Output

How many students? 5
Marks: 60 67 74 81 88
Average: 74.00

The allocation pattern

  1. Requestp = malloc(count * sizeof *p)
  2. Checkif (p == NULL) handle the error
  3. Usep[i] like an array
  4. Releasefree(p); p = NULL;
  • malloc(bytes) returns a void * to uninitialised memory, or NULL if it fails. In C there's no need to cast the result.
  • Writing sizeof *marks instead of sizeof(int) stays correct even if you later change the pointer's type.
  • The memory contains garbage until you write to it.

calloc

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int n = 6;
    int *votes = calloc((size_t)n, sizeof *votes);   // n elements, all set to zero
    if (votes == NULL) return 1;

    int ballots[] = {2, 4, 2, 0, 5, 2, 4};
    for (int i = 0; i < 7; i++) votes[ballots[i]]++;
    for (int c = 0; c < n; c++) printf("candidate %d: %d vote(s)\n", c, votes[c]);

    free(votes);
    return 0;
}

Output

candidate 0: 1 vote(s)
candidate 1: 0 vote(s)
candidate 2: 3 vote(s)
candidate 3: 0 vote(s)
candidate 4: 2 vote(s)
candidate 5: 1 vote(s)
malloc(size)calloc(count, size)
Argumentstotal bytesnumber of elements and size of each
Initial contentsgarbageall bytes zero
Overflow checkyou must check count × size yourselfchecks count × size for overflow
Use whenyou'll fill every element anywayyou need zeros (counters, flags)

Returning heap memory from a function

Unlike a local array, heap memory survives after the function returns – so a function can create data and hand it to the caller, who becomes responsible for freeing it:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *make_greeting(const char *name) {
    size_t len = strlen("Hello, ") + strlen(name) + strlen("!") + 1;   // +1 for '\0'
    char *s = malloc(len);
    if (s == NULL) return NULL;
    snprintf(s, len, "Hello, %s!", name);
    return s;                      // the caller must free this
}

int main(void) {
    char *msg = make_greeting("Meera");
    if (msg != NULL) {
        printf("%s (%zu chars)\n", msg, strlen(msg));
        free(msg);
    }
    return 0;
}

Output

Hello, Meera! (13 chars)

Who frees it?

Every malloc/calloc/realloc needs exactly one matching free. Decide and document who owns each block – "the caller must free the returned string" – just as the standard library documents it for functions like strdup.

Practice

Try it yourself

  1. Read n, allocate n doubles, store the squares of 1…n and print their sum.

    Show solution
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(void) {
        int n;
        printf("n: ");
        scanf("%d", &n);
        double *sq = malloc((size_t)n * sizeof *sq);
        if (sq == NULL) return 1;
        double sum = 0;
        for (int i = 0; i < n; i++) { sq[i] = (double)(i + 1) * (i + 1); sum += sq[i]; }
        printf("sum of squares 1..%d = %.0f\n", n, sum);
        free(sq);
        return 0;
    }

    Output

    n: 10
    sum of squares 1..10 = 385

Quick check

What does malloc return when it fails?

NULL.

malloc vs calloc?

malloc takes a byte count and leaves memory uninitialised; calloc takes count and size and zeroes the memory.

When is heap memory released?

Only when you call free (or the program ends).

Summary

  • The heap gives you memory sized at run time that lives until you free it.
  • malloc gives uninitialised memory, calloc gives zeroed memory; always check for NULL.
  • Every allocation needs one free; set the pointer to NULL afterwards.

Finished this lesson?

Mark it complete to track your progress, then carry on with the next lesson.

Next lesson

Search LearnFrenzy

Esc

Quick links