Menu
CoddyTech

C Memory Management Interview Questions

Dynamic allocation, stack and heap, leaks and the mistakes that cause crashes.

10 questions
  1. What is the difference between stack and heap memory in C?

    The stack holds locals and call frames, freed automatically on return; it is fast and small (8 MB for the main thread on most Linux systems, 1 MB on Windows by the linker default, 128 KiB for new threads on musl). The heap holds malloc memory that lives until free. Use the heap when the size is known only at runtime or the data must outlive the function. See stack vs heap.

  2. What is the difference between malloc, calloc and realloc?

    All three return NULL on failure. malloc(size) gives uninitialized memory, calloc(count, size) zeroed memory, and realloc(p, size) resizes a block, moving it if needed.

    C
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(void) {
        int *a = calloc(4, sizeof *a);          /* 4 ints, all zero */
        if (!a) return 1;
        for (int i = 0; i < 4; i++) a[i] += i;
    
        int *bigger = realloc(a, 6 * sizeof *a); /* grow to 6 ints */
        if (!bigger) { free(a); return 1; }
        a = bigger;
        a[4] = 40; a[5] = 50;                    /* new part is uninitialized, so set it */
    
        for (int i = 0; i < 6; i++) printf("%d ", a[i]);
        printf("\n");
        free(a);
        return 0;
    }

    It prints 0 1 2 3 40 50. calloc returns NULL if count * size overflows (mainstream libcs check it and C23 requires it). See calloc and realloc.

    Practice it: Merge Sorted Array

  3. What is wrong with p = realloc(p, new_size);?

    If realloc fails it returns NULL and keeps the old block, so assigning straight to p leaks it.

    int *tmp = realloc(p, new_size);
    if (tmp == NULL) {
        /* p is still valid: report the error, keep or free p */
        free(p);
        return -1;
    }
    p = tmp;
    

    Avoid realloc(p, 0) too: glibc frees p and returns NULL, musl returns a non-null pointer to a minimal block, and C23 makes the call undefined (see realloc on cppreference).

  4. What is a memory leak, and how do you find one in C?

    A leak is heap memory still allocated that the program can no longer reach, because the last pointer to it was lost before free.

    void leak(void) {
        char *buf = malloc(100);
        if (!buf) return;
        if (something_failed()) return;   /* buf is leaked on this path */
        free(buf);
    }
    

    Find leaks with Valgrind (valgrind --leak-check=full ./app) or AddressSanitizer (gcc -fsanitize=address -g). Avoid them with one owner per allocation and a single cleanup path (goto cleanup;). See memory leaks.

  5. What happens if you call free twice on the same pointer, or use memory after freeing it?

    Both are undefined behavior. A double free can corrupt the allocator's lists, which attackers exploit; use after free touches memory that may belong to another allocation. free(NULL) does nothing, so setting the pointer to NULL after free makes a second free harmless. AddressSanitizer reports both bugs at the exact line.

  6. Why is returning the address of a local variable a bug?

    The local's stack frame is released on return, so the pointer dangles and reading through it is undefined behavior.

    char *bad_name(void) {
        char name[16] = "coddy";
        return name;            /* GCC warns: function returns address of local variable */
    }
    

    Let the caller pass a buffer instead (the standard library's usual choice), or return malloc memory the caller frees.

  7. What causes a segmentation fault in C?

    The operating system stops a process that touched memory it may not access. In C it is a symptom of undefined behavior: dereferencing NULL or an uninitialized pointer, writing to a string literal, going past an array, using freed memory, or a stack overflow. An out-of-bounds write inside your own memory may not crash at all. Debug with -fsanitize=address, or gdb and bt. See segmentation faults.

  8. Describe the memory layout of a C program.

    From low to high addresses on Linux: text (machine code), data (globals and statics with a non-zero initializer), BSS (zero or uninitialized ones, zeroed at startup and taking no space in the file), the heap growing up, shared libraries and mmap regions, and the stack growing down. So static int big[1000000]; grows BSS but not the executable; with = {1} the file grows by 4 MB.

  9. How does malloc work, and how does free know the size of the block?

    It depends on the libc. glibc keeps a small header before each block with its size, and free(p) reads the bytes before p; musl's mallocng and jemalloc find the size from the group or page the address belongs to. Either way, pass back exactly what malloc returned. Freed blocks go to free lists or size-class bins for reuse, and glibc serves requests above a threshold (128 KiB at start, adjusted at run time) with their own mmap, returned to the kernel on free.

  10. What does malloc(0) return?

    It is implementation-defined: either NULL, or a unique pointer you must not dereference but must free. glibc and musl return non-NULL, but portable code cannot rely on it, so a size that can be 0 needs its own check.

    size_t n = count_items();
    int *items = malloc(n * sizeof *items);
    if (items == NULL && n != 0) {
        /* a real allocation failure */
    }
    

    Otherwise an empty list looks like an allocation failure.

Coddy programming languages illustration

Learn to code with Coddy

Get started