0 · Recall Warm-up
Answer from memory first. Answers are in the Answer Vault at the bottom.
- What does
p->xmean? from Lesson 1.6 - Where is
a[i][j]inint a[R][C]? from Lesson 1.5.2 - Why is
printf("%d", *p)wrong if p is NULL? from Lesson 1.4.1
1 · The Hook
🎣
A wedding caterer does not know until the morning whether 80 or 800 guests will come. Reserving tables for 800 every time wastes space; reserving 80 might be too few. Programs face the same problem: the amount of data is often known only while the program runs. So C lets a program ask for memory at run time, exactly as much as it needs, and hand it back later.
2 · Predict First
🤔
A function creates int local = 5; and returns &local. The caller then prints *p. Is 5 guaranteed?
Make a guess in your head. The answer opens Section 3.
3 · Core Concept
💡
Predict First — the answer
No. local lived in the function’s stack frame, which is popped on return. The pointer now points to dead memory: a dangling pointer. Reading it is undefined behavior. Memory from malloc does not have this problem.
The heap
Besides code, statics/globals and the stack, a program has a fourth region, the heap: a pool of memory handed out on request. Heap memory lives until the program explicitly frees it, regardless of which function asked for it.
malloc, calloc, realloc, free
| Call (stdlib.h) | Does |
|---|---|
malloc(n) | reserves n bytes, contents garbage; returns a void * (convertible to any pointer type) or NULL if it fails |
calloc(k, size) | reserves k × size bytes, all set to 0 |
realloc(p, n) | resizes the block to n bytes, keeping the old contents; may move it and return a new address |
free(p) | gives the block back; p itself still holds the old address |
int n = 5, i;
int *a = malloc(n * sizeof(int));
if (a == NULL) return 1;
for (i = 0; i < n; i++)
a[i] = i * i;
printf("%d %d\n", a[2], a[4]);
free(a);
Output
4 16
Always use sizeof (n * sizeof(int)), and check for NULL.
int *c = calloc(4, sizeof(int));
int *m = malloc(2 * sizeof(int));
m[0] = 7; m[1] = 8;
m = realloc(m, 4 * sizeof(int));
m[2] = 9; m[3] = 10;
printf("%d %d %d %d | %d %d %d %d\n", c[0], c[1], c[2], c[3], m[0], m[1], m[2], m[3]);
free(c);
free(m);
Output
0 0 0 0 | 7 8 9 10
Stack vs heap
| Stack (automatic) | Heap (dynamic) | |
|---|---|---|
| Created | on entering a block/call | by malloc/calloc/realloc |
| Destroyed | automatically on leaving | only by free |
| Size | fixed when compiled | chosen at run time |
| Speed | very fast | slower (bookkeeping) |
| Typical bug | returning the address of a local | leaks, dangling pointers, double free |
Returning heap memory is fine
int *makeArray(int n)
{
int *p = malloc(n * sizeof(int));
int i;
for (i = 0; i < n; i++)
p[i] = 10 * (i + 1);
return p; /* fine: heap memory outlives the call */
}
int main(void)
{
int *v = makeArray(3);
printf("%d %d %d\n", v[0], v[1], v[2]);
free(v);
return 0;
}
Output
10 20 30
The three classic bugs
- Dangling pointer: a pointer to memory that no longer exists (freed heap block, or a popped stack frame). Using it is undefined behavior. Setting
p = NULLafter free helps. - Memory leak: losing the last pointer to a block without freeing it (
p = malloc(…); p = malloc(…);). The block can never be freed; long-running programs slowly run out of memory. - Double free: calling free twice on the same block: undefined behavior. Watch out when two pointers share one block.
A 2-D table built at run time
An array of row pointers, each row a separate block:
int rows = 3, cols = 4, i, j;
int **g = malloc(rows * sizeof(int *));
for (i = 0; i < rows; i++)
g[i] = malloc(cols * sizeof(int));
for (i = 0; i < rows; i++)
for (j = 0; j < cols; j++)
g[i][j] = i * cols + j;
printf("%d %d\n", g[2][1], g[1][3]);
for (i = 0; i < rows; i++)
free(g[i]);
free(g);
Output
9 7
Free the rows first, then the array of row pointers.
4 · Visual
The four regions of a running C program (a common layout; the exact arrangement depends on the system).
Memory leak: Dangling pointer after free:
p = malloc(16); p --> [block A] int *p = malloc(4); p --> [block]
p = malloc(16); p --> [block B] int *q = p; q --> [block]
[block A] <-- free(p); p, q --> [freed!]
nobody points here: *q = 1; undefined behavior (q dangles)
it can never be freed free(q); undefined: double free
Leaks lose memory; dangling pointers and double frees corrupt it.
5 · Worked Examples
Example 1 Easy
What does this print?
int n = 5, i;
int *a = malloc(n * sizeof(int));
if (a == NULL) return 1;
for (i = 0; i < n; i++)
a[i] = i * i;
printf("%d %d\n", a[2], a[4]);
free(a);
Solution
a[i] = i²: a[2] = 4, a[4] = 16.
Output
4 16
Example 2 Medium
Which function is correct, and what is wrong with the others?
int *f1(void) { int x = 7; return &x; }
int *f2(void) { int *p = malloc(sizeof(int)); *p = 7; return p; }
int *f3(void) { static int y = 7; return &y; }
int *f4(void) { int *p = malloc(sizeof(int)); *p = 7; free(p); return p; }
Solution
f2 and f3 are correct: heap memory and static variables both outlive the call. f1 returns the address of a local in a popped frame (dangling). f4 frees the block and then returns a dangling pointer.
Example 3 GATE
What does this print, and what does the code at the end protect against?
int *p = malloc(sizeof(int));
int *q = p;
*q = 42;
printf("%d\n", *p);
free(p);
p = NULL;
q = NULL;
Solution
q is a second name for the same block: *q = 42 makes *p 42. After free(p) both pointers dangle; setting both to NULL ensures nobody uses or frees the block again.
Output
42
6 · GATE Traps
⚠️
- malloc does not zero memory; calloc does.
- realloc may move the block: always use its return value.
- free(p) does not change p; it now dangles. Set it to NULL.
- Freeing a block reached through two pointers once is enough; freeing it twice is undefined.
- Returning the address of an automatic local gives a dangling pointer; returning malloc’d or static memory is fine.
- Every malloc needs exactly one matching free, or the memory leaks.
8 · Memory Hook
🧠
“The stack cleans up after you; the heap never does.” Heap memory is a library book: borrow (malloc), use it, return it (free) exactly once, and never read a book you already returned.
9 · Connect the Dots
Lesson 1.6 built self-referential records; now they can be created one by one while the program runs. The C phase ends with two tools that work before and around the compiler. Next lesson answers: how can text be replaced in the program before it is compiled, and how can a function be stored in a variable?
10 · Self-Test
GATE format. Try every question before opening the vault.
Q1MCQ1 markcalloc
What does calloc(5, sizeof(int)) give?
- (A) 20 bytes, all zero (4-byte ints)
- (B) 20 bytes, garbage
- (C) 5 ints, each 5
- (D) 5 bytes, garbage
Q2MCQ2 marksDangling
Which function returns a pointer that is safe to use?
- (A)
int *f(void){ int x = 1; return &x; } - (B)
int *f(void){ static int x = 1; return &x; } - (C)
int *f(void){ int *p = malloc(4); free(p); return p; } - (D)
int *f(void){ int a[3] = {1}; return a; }
Q3MCQ1 markLeak
Which line causes a memory leak (p was set by malloc and not yet freed)?
- (A)
free(p); - (B)
p[0] = 1; - (C)
p = NULL; - (D)
q = p; free(q);
Q4MCQ2 marksOutput
What does this print?
int *c = calloc(4, sizeof(int));
int *m = malloc(2 * sizeof(int));
m[0] = 7; m[1] = 8;
m = realloc(m, 4 * sizeof(int));
m[2] = 9; m[3] = 10;
printf("%d %d %d %d | %d %d %d %d\n", c[0], c[1], c[2], c[3], m[0], m[1], m[2], m[3]);
free(c);
free(m);
- (A)
0 0 0 0 | 7 8 9 10 - (B)
0 0 0 0 | 7 8 0 0 - (C)
garbage | 7 8 9 10 - (D)
0 0 0 0 | 9 10 7 8
Q5MSQ1 markHeap
Which statements are true?
- (A) free(p) sets p to NULL.
- (B) malloc returns NULL when it cannot allocate.
- (C) realloc may return a different address.
- (D) Heap memory lives until it is freed.
11 · Rule Card
- Regions: code, static data, heap (malloc), stack (frames).
- malloc(n) garbage; calloc(k, s) zeroed; realloc(p, n) may move; free(p).
- Use n * sizeof(T); check NULL; use realloc’s result.
- Heap lives until free; stack locals die on return.
- Dangling: using freed/popped memory. Leak: losing the last pointer. Double free: freeing twice. All undefined or wasteful.
- After free(p), set p = NULL.
12 · Concept Ledger
Unlocked in this lesson. From here on, these terms may be used.
heapmalloccallocreallocfreevoid * from mallocdangling pointermemory leakdouble freestack vs heap
13 · Answer Vault
Answer Vault
Try the questions first. Open when you are ready to check.
Recall Warm-up
- (*p).x: the member x of the struct p points to.
- B + (i·C + j)·w.
- Dereferencing NULL is undefined behavior.
Self-Test
Q1 Answer: (A)1 mark
calloc zero-fills k × size bytes.
- (B) is wrong: calloc zeroes the memory.
- (C) is wrong: They are zero.
- (D) is wrong: It reserves 5 ints, 20 bytes.
Re-read: Lesson 1.7 — Dynamic memory: malloc, calloc, realloc, free; stack vs heap; dangling pointers, memory leaks, double free
Q2 Answer: (B)2 marks
A static lives for the whole run.
- (A) is wrong: Local in a popped frame.
- (C) is wrong: Freed before returning.
- (D) is wrong: The local array dies with the frame.
Re-read: Lesson 1.7 — Dynamic memory: malloc, calloc, realloc, free; stack vs heap; dangling pointers, memory leaks, double free
Q3 Answer: (C)1 mark
The last pointer to the block is lost without free.
- (A) is wrong: That releases the block.
- (B) is wrong: Ordinary use.
- (D) is wrong: The block is freed through q.
Re-read: Lesson 1.7 — Dynamic memory: malloc, calloc, realloc, free; stack vs heap; dangling pointers, memory leaks, double free
Q4 Answer: (A)2 marks
calloc zeroes; realloc keeps 7, 8 and the new cells are then set to 9, 10.
Output
0 0 0 0 | 7 8 9 10
- (B) is wrong: m[2] and m[3] are assigned after realloc.
- (C) is wrong: calloc zeroes its block.
- (D) is wrong: realloc preserves order.
Re-read: Lesson 1.7 — Dynamic memory: malloc, calloc, realloc, free; stack vs heap; dangling pointers, memory leaks, double free
Q5 Answer: (B) (C) (D)1 mark
free leaves p unchanged (dangling).
- (A) is wrong: p keeps the old address.
Re-read: Lesson 1.7 — Dynamic memory: malloc, calloc, realloc, free; stack vs heap; dangling pointers, memory leaks, double free