notesonly.in

One notebook for every subject — open it anywhere.

Log in

Pointers and Dynamic Memory: Complete Beginner's Guide

A pointer is a variable that stores a memory address instead of an ordinary value. With the & operator you get a variable's address, and with the * operator you read or write the value at the address a pointer holds. Dynamic memory is memory requested at run time with malloc/calloc, resized with realloc and released with free — unlike arrays, its size can be decided while the program is running.

Pointers are C's superpower: they enable arrays, strings, linked lists and trees, let functions modify caller variables, and avoid copying large data. Dynamic memory matters because input sizes are unknown at compile time — you cannot declare an array for "however many students enrol" until the program runs.

Key Concepts

  • Declaration: int *p means "pointer to int"; int x = 10; p = &x stores x's address in p.
  • Dereference: *p reads/writes the value at p's address — so *p = 20 changes x itself to 20.
  • Pointer arithmetic: for int *p, p + 1 moves forward by sizeof(int) = 4 bytes, landing on the next integer, not the next byte.
  • malloc(size): reserves uninitialised bytes; calloc(n, size): reserves and zeroes them; realloc: grows/shrinks a block; free: releases it.
  • Memory bugs: leak (never freed — grows until the program dies), dangling pointer (used after free), double free (freeing twice crashes), NULL dereference.

How It Works

How dynamic allocation serves five integers:

  1. int *p = (int *)malloc(5 * sizeof(int)) asks the OS for 5 × 4 = 20 bytes and returns the block's address into p.
  2. Always check p != NULL — malloc returns NULL when memory runs out, and dereferencing NULL crashes.
  3. Use it like an array: p[0] = 10; … p[4] = 50 — the block behaves exactly like int p[5].
  4. free(p) returns the 20 bytes to the OS; after that, p is dangling and must not be used (set p = NULL for safety).

Worked Example

Predict the output:

int a = 10;<br>int *p = &amp;a;<br>*p = 20;<br>printf("%d %d", a, *p);

  1. a holds 10; p holds a's address, so *p is an alias for a.
  2. *p = 20 writes 20 through the pointer — directly into a's memory cell.
  3. a is now 20, and *p reads that same cell: 20.

Output: 20 20. One variable, two names — that aliasing is why pointers let functions modify caller data.

Common Misconceptions

  • "Pointers are just for experts; I can avoid them." In C you cannot — arrays, strings and function parameters all decay to or need pointers; avoiding them means avoiding C itself.
  • "malloc'd memory starts at zero." No — malloc leaves garbage; only calloc zeroes the block. Reading uninitialised malloc memory is a classic bug.
  • "The OS frees everything, so free() is optional." The OS reclaims memory only when the program exits; a long-running server that never frees will slowly eat all RAM and die.

Real-World Applications

  • Data structures: linked lists, trees and graphs are webs of pointers; dynamic allocation grows them node by node.
  • Operating systems: kernels manage process memory with pointer arithmetic at massive scale.
  • Games and graphics: textures and meshes are malloc'd buffers manipulated through pointers for speed.
  • Servers: web servers allocate per-request buffers dynamically since request sizes vary wildly.

A pointer holds an address; &amp; takes one, * follows one, and pointer arithmetic strides by the pointed-to type's size. malloc, calloc, realloc and free give you memory sized at run time — with the strict contract that every allocation is checked for NULL and eventually freed. Master this contract and you master C's deepest and most powerful idea.