Own every byte you allocate
Interviewers check that you know where data lives, how to allocate and resize safely, and how to prevent and find leaks, dangling pointers and overflows.
- LayoutText, data, BSS, heap and stack.
- Allocationmalloc, calloc, realloc and free.
- SafetyLeaks, dangling pointers, overflows and tools.
Memory management is the heart of C — and the source of its most serious bugs. Interviewers for embedded, systems and product roles always ask how you allocate, resize and free memory safely, and how you find leaks and corruption.
1. What is the memory layout of a C program?
From low to high addresses, typically: the text segment (code, read-only), initialised data (globals and statics with values), BSS (uninitialised globals and statics, zeroed), the heap (grows up; malloc), and the stack (grows down; local variables and function frames). Knowing where a variable lives explains its lifetime.
int counter = 5; // initialised data
int total; // BSS (zero)
int main(void) {
int local = 1; // stack
int *arr = malloc(10 * sizeof *arr); // heap
static int calls; // BSS, lives for the whole program
free(arr);
return 0;
}2. malloc vs calloc vs realloc?
malloc(size) allocates uninitialised memory. calloc(n, size) allocates zeroed memory for n elements and checks the multiplication for overflow. realloc(ptr, size) resizes a block, possibly moving it; it returns NULL on failure and leaves the original block valid. All return void*, which converts to any object pointer in C without a cast.
int *scores = calloc(5, sizeof *scores); // [0,0,0,0,0]
if (!scores) return -1;
int *bigger = realloc(scores, 10 * sizeof *bigger);
if (!bigger) { // original block is still valid here
free(scores);
return -1;
}
scores = bigger;3. Why must you check the return value of malloc?
Allocation can fail and return NULL (out of memory, or an absurd size from a bug). Dereferencing NULL is undefined behaviour — usually a crash. Always check, and handle the failure (clean up and report an error).
4. What is a memory leak and how do you prevent it?
Memory allocated and never freed, typically because the last pointer to it was overwritten or a function returned early. Long-running programs eventually run out of memory. Prevent it with clear ownership rules (who frees what), a single cleanup path (goto cleanup is idiomatic in C), and tools such as Valgrind or AddressSanitizer.
int process(const char *path) {
int rc = -1;
char *buf = NULL;
FILE *f = fopen(path, "r");
if (!f) goto cleanup;
buf = malloc(4096);
if (!buf) goto cleanup;
/* ... use f and buf ... */
rc = 0;
cleanup:
free(buf); // free(NULL) is safe
if (f) fclose(f);
return rc;
}5. What are dangling pointers and double free?
A dangling pointer still points to memory that has been freed (or to a local variable that went out of scope); using it is undefined behaviour. A double free frees the same block twice and can corrupt the allocator. Set pointers to NULL after freeing and never return the address of a local variable.
char *make_name(void) {
char name[] = "Asha";
return name; // BUG: dangling — name dies when the function returns
}
char *make_name_ok(void) {
char *name = malloc(5);
if (name) strcpy(name, "Asha");
return name; // caller must free
}
free(p);
p = NULL; // prevents accidental reuse / double free6. How do you allocate a 2D array dynamically?
Either an array of row pointers (flexible, each row allocated separately) or one contiguous block indexed manually (faster, one allocation, one free). The contiguous version is usually better.
int rows = 3, cols = 4;
int *grid = malloc((size_t)rows * cols * sizeof *grid); // one block
if (!grid) return -1;
for (int r = 0; r < rows; r++)
for (int c = 0; c < cols; c++)
grid[r * cols + c] = r + c;
free(grid);7. What is a buffer overflow and how do you avoid it?
Writing past the end of an array — the classic cause of crashes and security holes. Avoid gets (removed from C11) and unbounded strcpy/sprintf; use fgets, snprintf and explicit length checks, and compile with warnings and sanitizers.
char name[16];
if (fgets(name, sizeof name, stdin)) {
name[strcspn(name, "\n")] = '\0'; // strip newline
}
char msg[64];
snprintf(msg, sizeof msg, "Hello, %s!", name); // never overflows msg8. How do you find memory bugs?
Compile with warnings (-Wall -Wextra) and run tests under AddressSanitizer (-fsanitize=address), which catches overflows, use-after-free and leaks with exact line numbers, or under Valgrind. Static analysers (clang-tidy, cppcheck) catch more before running.
gcc -g -Wall -Wextra -fsanitize=address,undefined app.c -o app && ./app
valgrind --leak-check=full ./appRemember
Key points
- Check every allocation
malloc can return NULL.
- realloc into a temporary
Do not lose the original on failure.
- NULL after free
Prevents use-after-free and double free.
- Use sanitizers
ASan and Valgrind find bugs fast.
Interview drill
Follow-up questions
What the interviewer asks after your first answer. Turn on practice mode, answer each one aloud, then reveal.
-
1 What does free(NULL) do? Basic
Nothing — it is defined to be safe, which simplifies cleanup code.
-
2 Does free() return memory to the operating system? Intermediate
Usually not immediately; the allocator keeps it for future allocations. Large blocks may be returned (implementation-specific).
-
3 What is the difference between stack and heap allocation? Basic
Stack memory is automatic, fast and freed when the function returns, but limited in size. Heap memory lives until freed, can be large and resized, but is slower and must be managed manually.
-
4 What is memory fragmentation? Advanced
Free memory split into small non-contiguous pieces, so a large allocation fails despite enough total free memory. Pools and fixed-size allocators reduce it in embedded systems.
-
5 Why is sizeof *ptr preferred over sizeof(int) in malloc? Intermediate
It stays correct if the pointer's type changes later, removing a common source of bugs.
-
6 What is a wild pointer? Basic
An uninitialised pointer holding a garbage address. Always initialise pointers, to NULL if nothing else.