Must-Solve Conceptual C Questions for Placement Interviews
Eight conceptual C questions on pointers, undefined behavior, sizeof, and switch fall-through, with answers, C standard citations, and output traces.
Interviewers use conceptual C questions to test whether a candidate understands how the language works under the hood, not just whether they can write a loop.
Why Conceptual C Questions Appear in Every Placement Round
Syntax questions have a ceiling. A candidate who memorises printf format specifiers passes a syntax test but collapses the moment a recruiter asks what the output of a one-liner with two i++ arguments is. That’s the ceiling. Conceptual questions separate those who hit it from those who understand the rules beneath it.
Eight questions cover the areas that appear most often in placement tests at product and service companies: pointer mechanics, struct memory layout, undefined behavior, and classic language gotchas. Each answer includes a C11 standard reference so you can follow the chain of authority, not just trust the answer.
Pointer Mechanics: Function Pointers, Double Pointers, Pointer-to-Array
Function Pointer Declaration and Call
- Question: What is the output of this program?
#include <stdio.h>
void greet(void) { printf("Hello\n"); }
int main(void) {
void (*fp)(void) = greet;
(*fp)();
return 0;
}
- Output:
Hello - Explanation:
fpis a function pointer. Assigningfp = greetstores the address ofgreet. Both(*fp)()andfp()are valid call syntax; the C standard (via cppreference on function pointers) specifies that a function designator is implicitly converted to a pointer to the function (C11 §6.3.2.1p4). The interview wrinkle: most candidates tryfp()and pass, but some ask whether(*fp)()is also correct. It is.
Double Pointer Dereference
- Question: What does this print?
#include <stdio.h>
int main(void) {
int a = 10;
int *p = &a;
int **q = &p;
printf("%d %d %d", a, *p, **q);
return 0;
}
- Output:
10 10 10 - Explanation:
pholds the address ofa.qholds the address ofp. Dereferencing*pyieldsa’s value. Dereferencing**qfollows two indirections:*qgivesp, then*(*q)givesa. All three expressions resolve to the same integer.
Pointer-to-Array vs Array of Pointers
-
Question: What is the difference between
`int (*arr)[5]`and`int *arr[5]`? -
Answer:
`int (*arr)[5]`—arris a pointer to an array of 5intvalues. One pointer variable. On a 64-bit system,sizeof(arr)is 8 bytes.`int *arr[5]`—arris an array of 5 pointers toint. Five pointer variables. On a 64-bit system,sizeof(arr)is 40 bytes.- The parentheses around
*arrbind the dereference toarrbefore the subscript operator, makingarra pointer rather than an array. Read from the identifier outward using the clockwise/spiral rule.
For a deeper look at how pointer and array types interact in parameter declarations, see FACE Prep’s coverage of pointer and array interactions in C.
Memory Layout: Struct Padding and sizeof
- Question: What does this print, and why?
#include <stdio.h>
struct Test {
char a;
int b;
char c;
};
int main(void) {
printf("%zu\n", sizeof(struct Test));
return 0;
}
- Output:
12(on most 32-bit and 64-bit systems with default alignment) - Step-by-step layout:
char a— 1 byte, placed at offset 0.- Padding — 3 bytes added so the next field is 4-byte aligned.
int b— 4 bytes, placed at offset 4.char c— 1 byte, placed at offset 8.- Trailing padding — 3 bytes added so the struct size is a multiple of its largest member alignment (4).
- Total: 12 bytes.
- C11 rule: §6.7.2.1p15 permits unnamed padding within a structure to satisfy alignment requirements. The amount of padding is implementation-defined;
sizeofis the only portable way to measure a struct’s size. The cppreference struct reference shows common padding patterns. - Interview follow-up: declaring members in decreasing size order (
int,char,char) reduces padding and can shrink the struct to 8 bytes.
Undefined Behavior: Three Traps Interviewers Use
Post-Increment in the Same Function Call
- Question: What is the output?
#include <stdio.h>
int main(void) {
int i = 5;
printf("%d %d\n", i++, i++);
return 0;
}
- Output: undefined — compilers may print
5 6,6 5,5 5, or anything else. - C11 rule: §6.5p2 — “Between the previous and next sequence point, the value of a scalar object shall be modified at most once.” The two
i++expressions modifyitwice with no sequence point between them, so the behavior is undefined. Per cppreference’s evaluation order page, the order in which function arguments are evaluated is unspecified, and modifying the same object twice is outright undefined. GCC and Clang produce different output here with different optimisation flags.
Signed Integer Overflow
- Question: Is this program correct?
#include <limits.h>
#include <stdio.h>
int main(void) {
int x = INT_MAX;
printf("%d\n", x + 1);
return 0;
}
- Answer: The expression
x + 1is undefined behavior. - C11 rule: §6.5p5 — if arithmetic result is not representable in the result type, the behavior is undefined. For signed
int,INT_MAX + 1wraps around toINT_MINon most architectures in debug builds, but an optimizing compiler may legally assume signed overflow never occurs. This allows it to simplifyif (x + 1 > x)toif (1)— eliminating a check the programmer thought was a safety net. - Practical note: use
unsigned intif wrapping is intentional, or check with__builtin_add_overflowin GCC/Clang.
Use-After-Free
- Question: What is wrong with this?
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int *p = (int *)malloc(sizeof(int));
*p = 42;
free(p);
printf("%d\n", *p); /* reading after free */
return 0;
}
- Answer: Dereferencing
pafterfree(p)is undefined behavior. The memory has been returned to the allocator; it may have been overwritten, reused, or left intact. Any output is possible. The fix: setp = NULLimmediately afterfree(p), then check before use.
Classic Gotchas: switch Fall-Through and void main
switch Fall-Through
- Question: What does this print?
#include <stdio.h>
int main(void) {
int x = 1;
switch (x) {
case 1: printf("one ");
case 2: printf("two ");
case 3: printf("three\n");
}
return 0;
}
- Output:
one two three - Explanation: After matching
case 1, control continues downward throughcase 2andcase 3because there is nobreak. This is correct C behavior, not a compiler quirk. Intentional fall-through is used in some state machines; unintentional fall-through is one of the most common placement-test traps. GCC emits-Wimplicit-fallthroughwith-Wallto flag unintended cases.
void main vs int main
-
Question: Is
void main(void)valid C? -
Answer: No, not in conforming C. C11 §5.1.2.2.1 specifies two acceptable hosted-program signatures:
int main(void)int main(int argc, char *argv[])- Any other form, including
void main(void), is implementation-defined at best and undefined behavior at worst. Most compilers accept it as an extension, but portable code usesint main(void)and returns an integer. The return value signals the OS the program’s exit status —0for success, non-zero for failure.
For a structured list of the questions that appear most often in technical rounds, FACE Prep’s most-asked C interview questions covers 31 programs with traced output. For additional gotchas around memory and error patterns, the common C programming errors guide is a useful companion read.
Understanding why INT_MAX + 1 is undefined, or why two i++ arguments produce unpredictable output, is exactly the kind of reasoning modern compilers reward, and that AI coding assistants can now explain on demand. If you want to explore these undefined-behavior cases interactively, ask an LLM to trace the optimizer’s reasoning step by step. TinkerLLM is a ₹299 sandbox built for that kind of structured technical experimentation, with no prior AI background needed and the C debugger prompts already pre-built.
Primary sources
Frequently asked questions
What is the difference between int (*arr)[5] and int *arr[5]?
int (*arr)[5] is a pointer to an array of 5 ints — one pointer variable. int *arr[5] is an array of 5 pointers to int — five pointer variables. The parentheses around *arr bind the dereference operator to arr before the subscript, making arr a pointer rather than an array.
Why is void main considered wrong in standard C?
C11 §5.1.2.2.1 lists only two conforming signatures: int main(void) and int main(int argc, char *argv[]). void main is accepted by many compilers as a vendor extension, but the behavior of the runtime after main returns is implementation-defined, not portable.
What happens when a switch case has no break in C?
Control falls through to the next case label and executes all subsequent statements until a break, return, or the end of the switch block. This is the correct fall-through behavior per the C standard, not a bug — but it's one of the most common sources of unintended output in placement tests.
Is signed integer overflow undefined behavior in C?
Yes. C11 §6.5p5 specifies that arithmetic overflow for signed integers is undefined behavior. The compiler may assume it never occurs and eliminate overflow checks. Use unsigned arithmetic or the __builtin_add_overflow GCC extension for safe addition.
How do I read a function pointer declaration in C?
Apply the clockwise/spiral rule: start at the identifier, move right then left. For void (*fp)(void): fp is a pointer (the * under parentheses), to a function taking no arguments (void), returning void. Assigning fp = myFunc stores the function address; calling (*fp)() or fp() both invoke it.
What is a dangling pointer and how is it different from a null pointer?
A dangling pointer holds the address of memory that has been freed or gone out of scope. Dereferencing it is undefined behavior. A null pointer holds 0 (or NULL) — dereferencing it is also undefined, but is at least predictable on most OSes (segfault). The fix for a dangling pointer is to set it to NULL immediately after free().
A self-paced playground for building with LLMs.
TinkerLLM is FACE Prep's sister property. A guided environment for shipping real LLM applications, the kind of project that earns a paragraph on your resume, not a line.
Try TinkerLLM (₹299 launch)