Many online tutorial sites publish outdated, copy-pasted lists of C interview questions that contain severe technical inaccuracies. If you walk into a technical interview at an embedded systems company or infrastructure team reciting answers from low-quality question dumps, you will fail the screen.
To pass a C engineering interview, you need to understand how the compiler, linker, and hardware behave. Below are the definitive answers to high-frequency technical questions, debunking common myths and providing verified C code.
Myth Buster: Does C Support Function Overloading?
The Short Answer: No. C does not support traditional function overloading.
In languages like C++ or Java, the compiler performs name mangling, generating internal symbol names that encode the function name alongside its parameter types. For example, sum(int, int) becomes something like _Z3sumii, allowing multiple functions with the same identifier to coexist.
In C, the compiler does not mangle symbols. A function named sum produces the exact linker symbol _sum. Attempting to write:
// THIS WILL NOT COMPILE IN C
int sum(int a, int b) { return a + b; }
float sum(float a, float b) { return a + b; } // Error: redefinition of 'sum'
results in a compile-time error. If an interviewer asks you how to achieve polymorphic behavior in modern C, explain C11 Type-Generic Expressions (_Generic). This demonstrates genuine language depth:
#include <stdio.h>
static inline int sum_int(int a, int b) { return a + b; }
static inline float sum_float(float a, float b) { return a + b; }
static inline double sum_double(double a, double b) { return a + b; }
// C11 generic selection macro
#define sum(x, y) _Generic((x), \
int: sum_int, \
float: sum_float, \
double: sum_double \
)(x, y)
int main(void) {
printf("Int sum: %d\n", sum(5, 10));
printf("Float sum: %.2f\n", sum(2.5f, 4.1f));
return 0;
}
Memory Layout: Stack, Heap, BSS, and Data Segments
Every compiled C binary maps into distinct virtual memory segments managed by the OS and runtime:
- Text (Code) Segment: Read-only region storing executable machine instructions.
- Data Segment: Contains global and static variables that are explicitly initialized by the programmer (for example,
static int counter = 42;). - BSS Segment (Block Started by Symbol): Contains uninitialized global and static variables (for example,
static int buffer[1024];). The operating system zero-fills this segment before execution starts. - Heap: Dynamically managed memory grown upwards via
malloc(),calloc(), andrealloc(). Must be explicitly freed. - Stack: Stores local stack frames, function arguments, and return addresses. Grows downwards on x86/ARM architectures and is automatically cleaned up when functions return.
Static Variables: Storage Duration vs Linkage Scope
The static keyword in C has two distinct meanings depending on where it is placed:
1. Static Local Variables (Storage Duration)
When declared inside a function body, static alters the variable storage duration from automatic (stack) to static (data segment). The variable is initialized exactly once when the program loads and preserves its state across calls:
#include <stdio.h>
int get_next_sequence_id(void) {
static int sequence = 1000; // Allocated in data segment, initialized once
return sequence++;
}
int main(void) {
printf("ID 1: %d\n", get_next_sequence_id()); // 1000
printf("ID 2: %d\n", get_next_sequence_id()); // 1001
return 0;
}
2. Static Global Variables and Functions (Internal Linkage)
When placed outside any function, static restricts the symbol visibility to the current translation unit (.c file). Other files compiled into the same program cannot link to or reference that symbol. This is C mechanism for encapsulation and information hiding.
Array Decay and Pointer Arithmetic
An array is not identical to a pointer, even though beginners frequently conflate them. In C, an array is a contiguous block of memory with a known size at compile time. In most expressions, the array identifier decays into a pointer to its first element.
#include <stdio.h>
void print_size(int arr[]) {
// Here, arr has decayed into a pointer (int *)
printf("Size inside function: %zu bytes\n", sizeof(arr)); // Prints 8 on 64-bit systems
}
int main(void) {
int numbers[10];
// Here, numbers has NOT decayed
printf("Size in main: %zu bytes\n", sizeof(numbers)); // Prints 40 bytes (10 * 4)
print_size(numbers);
return 0;
}
Because arrays decay into pointers when passed to functions, you must always pass the array length as an explicit secondary parameter.
Safe Input Handling: Why scanf("%s") Causes Remote Code Execution
Writing scanf("%s", buffer); is just as dangerous as calling gets(). It reads user input until encountering whitespace without checking the destination buffer boundary. If a user inputs 200 characters into a 16-character stack buffer, the excess bytes overwrite the function saved frame pointer and return address, creating a classic stack smashing exploit.
To safely capture input from stdin, use fgets() with explicit size limits and strip the trailing newline character:
#include <stdio.h>
#include <string.h>
#define BUFFER_SIZE 64
int safe_read_line(char *dest, size_t max_len) {
if (fgets(dest, (int)max_len, stdin) == NULL) {
return -1; // EOF or input error
}
// Remove trailing newline if present
size_t len = strlen(dest);
if (len > 0 && dest[len - 1] == '\n') {
dest[len - 1] = '\0';
}
return 0;
}
int main(void) {
char username[BUFFER_SIZE];
printf("Enter your handle: ");
if (safe_read_line(username, sizeof(username)) == 0) {
printf("Welcome, %s\n", username);
}
return 0;
}
Dynamic Memory: malloc() vs calloc() vs realloc()
Dynamic memory allocation requires rigorous checking:
malloc(size_t size): Allocates an uninitialized block of bytes. The allocated memory contains whatever arbitrary garbage data previously resided in those RAM cells.calloc(size_t num, size_t size): Allocates memory and explicitly sets all bits to zero. It also checks for integer overflow when computingnum * size, returning NULL if an overflow occurs.free(void *ptr): Deallocates the memory block. Passing a pointer tofree()twice (double-free) corrupts heap metadata and causes security vulnerabilities. Always set freed pointers toNULLif they remain in scope.
Summary: The Technical Interview Checklist
- Clarify pointer decay whenever arrays are passed across function boundaries.
- Never claim C supports function overloading; present C11
_Genericinstead. - Identify uninitialized memory risks and contrast malloc with calloc.
- Demonstrate defensive bounds checking with
fgetsinstead of gets or unprotected scanf.
Writing low-level C teaches you how the machine actually executes instructions in physical memory. When you understand pointers and memory layouts, mastering higher-level languages like TypeScript, Python, or Go becomes simple. Encode binary buffers with our free Base64 Encoder / Decoder, format structured payloads with our JSON Formatter, and sharpen your core problem-solving with our guide on Understanding Programming Logic and our Free Developer Tools.
