Placement Prep

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.

By FACE Prep Team 5 min read
c-programming placement-prep pointers undefined-behavior technical-interview data-structures

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: fp is a function pointer. Assigning fp = greet stores the address of greet. Both (*fp)() and fp() 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 try fp() 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: p holds the address of a. q holds the address of p. Dereferencing *p yields a’s value. Dereferencing **q follows two indirections: *q gives p, then *(*q) gives a. 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]`arr is a pointer to an array of 5 int values. One pointer variable. On a 64-bit system, sizeof(arr) is 8 bytes.
    • `int *arr[5]`arr is an array of 5 pointers to int. Five pointer variables. On a 64-bit system, sizeof(arr) is 40 bytes.
    • The parentheses around *arr bind the dereference to arr before the subscript operator, making arr a 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; sizeof is 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 modify i twice 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 + 1 is 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 + 1 wraps around to INT_MIN on most architectures in debug builds, but an optimizing compiler may legally assume signed overflow never occurs. This allows it to simplify if (x + 1 > x) to if (1) — eliminating a check the programmer thought was a safety net.
  • Practical note: use unsigned int if wrapping is intentional, or check with __builtin_add_overflow in 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 p after free(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: set p = NULL immediately after free(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 through case 2 and case 3 because there is no break. 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-fallthrough with -Wall to 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 uses int main(void) and returns an integer. The return value signals the OS the program’s exit status — 0 for 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().

Build AI projects

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)
Free AI Roadmap PDF