Part of C in 100s

C in 100 Seconds: malloc and free | Episode 20

Celest KimCelest Kim

Video: C in 100 Seconds: Dynamic Memory — malloc sizeof free | Episode 20 by Taught by Celeste AI - AI Coding Coach

Take the quiz on the full lesson page
Test what you've read · interactive walkthrough

C Dynamic Memory: malloc, sizeof, free

malloc(N * sizeof(int)) allocates N ints on the heap. free(p) releases. Every malloc needs a matching free or the memory leaks.

malloc and free are how C handles memory at runtime. Stack allocation (regular variables) is fast but limited; the heap is unlimited but you manage it yourself.

The basic shape

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

int main() {
  int *nums = malloc(5 * sizeof(int));

  for (int i = 0; i < 5; i++) {
    nums[i] = (i + 1) * 10;
  }

  for (int i = 0; i < 5; i++) {
    printf("nums[%d] = %d\n", i, nums[i]);
  }

  free(nums);
  printf("Memory freed.\n");

  return 0;
}

malloc

void *malloc(size_t size);

Allocates size bytes on the heap. Returns a pointer to the allocated memory, or NULL on failure.

The returned pointer is void *. You assign it to your typed pointer; the assignment implicitly casts.

int *nums = malloc(5 * sizeof(int));   // 20 bytes
double *vals = malloc(100 * sizeof(double));   // 800 bytes
char *buf = malloc(256);                // 256 bytes

Always multiply: count * sizeof(type). The compiler verifies the type via the assignment, but the math is yours.

sizeof

sizeof(type) returns the byte size of a type at compile time. Cross-platform-safe — handles 32-bit vs 64-bit int differences automatically.

sizeof(int)        // typically 4
sizeof(long)       // typically 4 or 8
sizeof(double)     // 8
sizeof(int *)      // 8 on 64-bit, 4 on 32-bit
sizeof(arr)        // total bytes of array (only in declaring scope)

Always check for NULL

int *nums = malloc(5 * sizeof(int));
if (nums == NULL) {
  fprintf(stderr, "out of memory\n");
  return 1;
}

malloc returns NULL when the allocation fails — typically because the system is out of memory. Real code always checks. For demo code, you might skip — but production code without NULL checks is broken.

A tip: define a wrapper.

void *xmalloc(size_t size) {
  void *p = malloc(size);
  if (p == NULL) {
    perror("malloc");
    exit(1);
  }
  return p;
}

xmalloc aborts on failure — useful for "if we can't allocate, we're done anyway" scenarios.

free

free(nums);
nums = NULL;   // good practice

free(p) releases the memory p points to. After free, the pointer is invalid — accessing it is undefined behavior.

Setting to NULL after free isn't required, but it converts use-after-free into a NULL-pointer crash, which is usually easier to debug than silent corruption.

Indexing the heap pointer

int *nums = malloc(5 * sizeof(int));
nums[0] = 10;
nums[1] = 20;
*(nums + 2) = 30;

After malloc, nums is just a pointer. You use [] indexing or pointer arithmetic — same as arrays. C doesn't distinguish "this came from malloc" vs "this is a stack array."

Stack vs heap

void demo() {
  int stack_arr[100];           // on the stack — fast, automatic cleanup
  int *heap_arr = malloc(100 * sizeof(int));   // on the heap — manual cleanup
  // ...
  free(heap_arr);
}
Stack Heap
Fast allocation (one register adjustment) Slower (free-list lookup)
Limited size (typical default ~8 MB) Limited only by available RAM
Automatic cleanup Manual free required
Local lifetime (destroyed at scope end) Lives until free
Size known at compile time (mostly) Size can be runtime-decided

Use stack for small, fixed-size, scope-limited data. Use heap for big, runtime-sized, or longer-lived data.

Why not always use the heap?

  • Cost. malloc/free are slow compared to stack allocation. Hot loops should avoid them.
  • Risk. Forgetting to free leaks memory. Freeing twice is undefined behavior. Pointers can go stale.
  • Fragmentation. Long-running programs that malloc/free aggressively can fragment the heap.

For most code, prefer stack allocation when it works. Reach for malloc when you need:

  • Size known only at runtime.
  • Data that outlives the current function.
  • Large allocations that would blow the stack.

sizeof on an allocated pointer

int *p = malloc(10 * sizeof(int));
size_t bytes = sizeof(p);     // 8 — pointer size
size_t elements = ???           // can't know — sizeof has no idea

Once you have a pointer to heap memory, the size of the allocation is lost as far as the C language is concerned. You must track the size yourself:

typedef struct {
  int *data;
  size_t size;
} IntList;

IntList list;
list.size = 10;
list.data = malloc(list.size * sizeof(int));

malloc returns uninitialized memory

int *nums = malloc(5 * sizeof(int));
printf("%d\n", nums[0]);   // garbage

malloc doesn't zero the memory. Whatever was there before is still there.

For zero-initialized memory, use calloc (next episode).

Common mistakes

Forgetting to free. Memory leak. For a long-running program, eventually OOM. Episode 22 dives into this.

Freeing twice. Double-free is undefined behavior — usually corrupts the heap and crashes later in a confusing place.

Using after free. free(p); printf("%d", *p); — undefined. Sometimes still works (the memory hasn't been reused yet), sometimes catastrophic.

malloc(N) instead of malloc(N * sizeof(int)). Allocates N bytes, not N ints. Reading arr[1] reads the second byte, not the second int.

Forgetting the NULL check. Allocation fails; pointer is NULL; dereference crashes.

Mixing malloc and new (in C++). Each must be paired with its corresponding free/delete. Don't delete a malloc'd pointer.

Not tracking the allocated size. No way to recover; you have to remember.

What's next

Episode 21: calloc and realloc. Variants for zero-initialized memory and resizing.

Recap

malloc(N * sizeof(type)) allocates on the heap; returns void * that you assign to a typed pointer. Always check for NULL. free(p) releases. Every malloc needs exactly one free. Set pointer to NULL after free for safety. Heap memory is uninitialized — use calloc for zeros. The size is lost; track it yourself. Stack allocation is faster and automatic; reach for the heap when stack won't do.

Next episode: calloc and realloc.

Ready? Take the quiz on the full lesson page →
Test what you've learned. Watch the lesson and try the interactive quiz on the same page.