Coding 101

Essential C Programming Interview Programs: Pointers, Memory, and Algorithms

DD
Ankur Ishwar
14 min read Updated Sep 7, 2026
c basic interview programs

Technical interviews in C evaluate something fundamentally different from interviews in JavaScript, Python, or Go. High-level languages abstract away memory layouts and operating system interactions. In C, interviewers want to see if you understand how hardware executes your code: stack versus heap allocations, CPU cache line alignment, pointer dereferencing, and undefined behavior.

If you are reviewing basic control flow and syntax first, take a look at our foundational guide on mastering C basic programs and the architectural origins in the history and importance of the C language.

Below are six core programming problems frequently asked during systems engineering, embedded firmware, and infrastructure interviews, accompanied by production-grade, compilable C code.

1. In-Place String Reversal with Double Pointers

The Objective: Reverse an ASCII string in-place without allocating a secondary buffer, avoiding stack overflow, and handling null or zero-length inputs gracefully.

Key Concepts: Pointer arithmetic, null termination checking, in-place temporary character swap.

#include <stdio.h>
#include <string.h>

void reverse_string(char *str) {
    if (str == NULL || *str == '\0') {
        return;
    }

    char *start = str;
    char *end = str + strlen(str) - 1;

    while (start < end) {
        char temp = *start;
        *start = *end;
        *end = temp;
        start++;
        end--;
    }
}

int main(void) {
    char message[] = "Dropout Developer";
    printf("Original: %s\n", message);
    
    reverse_string(message);
    printf("Reversed: %s\n", message);
    
    return 0;
}

Common Pitfall: Passing a string literal such as char *literal = "Hello"; reverse_string(literal); causes a segmentation fault on modern operating systems because string literals reside in the read-only data segment (.rodata). Always mutate character arrays allocated on the stack (char arr[]) or heap.

2. Reversing a Singly Linked List (Iterative O(N) Time, O(1) Space)

The Objective: Reverse the pointer chain of a singly linked list in a single pass without allocating additional nodes.

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

typedef struct Node {
    int data;
    struct Node *next;
} Node;

Node *reverse_linked_list(Node *head) {
    Node *prev = NULL;
    Node *current = head;
    Node *next_node = NULL;

    while (current != NULL) {
        next_node = current->next;
        current->next = prev;
        prev = current;
        current = next_node;
    }

    return prev;
}

void push_front(Node **head_ref, int new_data) {
    Node *new_node = (Node *)malloc(sizeof(Node));
    if (new_node == NULL) {
        perror("Failed to allocate memory for node");
        exit(EXIT_FAILURE);
    }
    new_node->data = new_data;
    new_node->next = *head_ref;
    *head_ref = new_node;
}

void print_list(const Node *node) {
    while (node != NULL) {
        printf("%d -> ", node->data);
        node = node->next;
    }
    printf("NULL\n");
}

void free_list(Node *head) {
    Node *current = head;
    while (current != NULL) {
        Node *temp = current;
        current = current->next;
        free(temp);
    }
}

Why Recursive Reversal is Dangerous: While recursive linked list reversal looks elegant on paper, it consumes O(N) stack frames. If the linked list contains one million elements, recursion triggers an unavoidable stack overflow crash. Production C code uses the iterative approach.

3. Safe Dynamic Array Resizing (realloc Pitfall)

The Objective: Build a dynamically growing vector in C that prevents memory leaks when memory is exhausted.

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

typedef struct {
    int *items;
    size_t count;
    size_t capacity;
} DynamicIntVector;

int vector_append(DynamicIntVector *vec, int value) {
    if (vec->count >= vec->capacity) {
        size_t new_capacity = (vec->capacity == 0) ? 4 : vec->capacity * 2;
        
        // Notice: never assign realloc directly to vec->items
        int *temp = (int *)realloc(vec->items, new_capacity * sizeof(int));
        if (temp == NULL) {
            return -1; // Allocation failed; original buffer remains intact
        }
        
        vec->items = temp;
        vec->capacity = new_capacity;
    }

    vec->items[vec->count++] = value;
    return 0;
}

void vector_destroy(DynamicIntVector *vec) {
    if (vec->items != NULL) {
        free(vec->items);
        vec->items = NULL;
    }
    vec->count = 0;
    vec->capacity = 0;
}

The Critical Bug to Point Out in Interviews: Writing vec->items = realloc(vec->items, new_size); introduces a severe memory leak. If realloc returns NULL, the pointer to the original memory block is overwritten with NULL, making it impossible to free the original allocation.

4. Fast Bit Manipulation: Brian Kernighan's Algorithm

The Objective: Count the number of set bits (1s) in a 32-bit unsigned integer in O(K) iterations, where K is the number of set bits, rather than iterating through all 32 bits.

#include <stdio.h>
#include <stdint.h>

int count_set_bits(uint32_t n) {
    int count = 0;
    while (n > 0) {
        // n & (n - 1) clears the lowest set bit in a single CPU instruction
        n = n & (n - 1);
        count++;
    }
    return count;
}

int is_power_of_two(uint32_t n) {
    // A power of two has exactly one set bit
    return (n > 0) && ((n & (n - 1)) == 0);
}

int main(void) {
    uint32_t value = 29; // Binary: 00011101 (4 set bits)
    printf("Set bits in %u: %d\n", value, count_set_bits(value));
    printf("Is 16 a power of 2? %s\n", is_power_of_two(16) ? "Yes" : "No");
    printf("Is 18 a power of 2? %s\n", is_power_of_two(18) ? "Yes" : "No");
    return 0;
}

5. Struct Padding and Memory Alignment

Interviewers frequently present a struct definition and ask for its sizeof output on a 64-bit architecture:

#include <stdio.h>

struct Unoptimized {
    char a;      // 1 byte
    // 3 bytes of compiler padding inserted here
    int b;       // 4 bytes
    char c;      // 1 byte
    // 7 bytes of compiler padding inserted here
    double d;    // 8 bytes
};

struct Optimized {
    double d;    // 8 bytes (aligned on 8-byte boundary)
    int b;       // 4 bytes
    char a;      // 1 byte
    char c;      // 1 byte
    // 2 bytes of tail padding to reach multiple of 8
};

int main(void) {
    printf("Unoptimized size: %zu bytes\n", sizeof(struct Unoptimized)); // Outputs 24 bytes
    printf("Optimized size: %zu bytes\n", sizeof(struct Optimized));     // Outputs 16 bytes
    return 0;
}

CPUs read memory efficiently when multi-byte values reside at memory addresses that are multiples of their size. By reordering struct fields from largest to smallest, you save substantial cache footprint across large data collections.

6. Type Punning: Inspecting IEEE 754 Float Representation

Directly casting (int)3.14f converts the value mathematically to 3. But what if an interviewer asks you to inspect the raw IEEE 754 32-bit floating point binary pattern? In modern C, the strict aliasing rule prohibits casting *(int *)&float_val. Instead, use a union or memcpy:

#include <stdio.h>
#include <string.h>
#include <stdint.h>

void print_float_bits(float f) {
    uint32_t bits;
    memcpy(&bits, &f, sizeof(bits)); // Safe under strict aliasing

    uint32_t sign = (bits >> 31) & 1;
    uint32_t exponent = (bits >> 23) & 0xFF;
    uint32_t mantissa = bits & 0x7FFFFF;

    printf("Float: %f\n", f);
    printf("Sign: %u | Exponent (raw): 0x%X | Mantissa: 0x%X\n", sign, exponent, mantissa);
}

int main(void) {
    print_float_bits(3.14159f);
    return 0;
}

Summary Checklist for Your C Interview

  • Never use gets(): It has no buffer limit checks and was formally removed from ISO C11. Always use fgets(buffer, sizeof(buffer), stdin).
  • Pair every malloc with free: Check for NULL immediately after every memory allocation call.
  • Understand Pointer Arithmetic: ptr + 1 advances by sizeof(*ptr) bytes, not 1 byte.
  • Beware of Off-By-One Strings: A string of length N requires an array of size N + 1 to store the terminating null character '\0'.

For more strategies on standing out in software engineering interviews without a Tier-1 degree, check out our guide on breaking the non-traditional path to a developer career.

Found this useful?
View all articles

Keep Reading

Related Articles

Learn with Dropout Developer

Build real software with AI

Step-by-step learning paths, vibe coding tutorials, and certified developer programs designed for the modern engineer.