1. What does setjmp and longjmp provide in C programming?
Answer: Non-local jumps — a low-level exception-handling mechanism that can jump back across multiple function call frames.
setjmp and longjmp (from <setjmp.h>) are the C way to “throw” across stack frames without normal returns:
setjmp(buf)saves the execution environment (stack pointer, instruction pointer, registers, signal mask) into ajmp_buf, and returns0the first time.longjmp(buf, value)restores that saved environment and jumps execution back to thesetjmppoint — unwinding any intermediate function frames.
jmp_buf env;
if (setjmp(env) == 0) {
do_work(); // deep call chain
} else {
// longjmp landed here, value != 0
handle_error();
}
It’s the classic error-handling idiom for C (used by old C codebases for exception-like flow). Caveats: local automatic variables modified between setjmp and longjmp may be indeterminate unless volatile; you can’t jump past the frame containing setjmp (that frame must still be alive). The interview answer: non-local jumps for exception-style control flow across function call frames.
2. What is the difference between passing arguments by value versus passing by reference (using pointers) in C?
Answer: C only supports pass-by-value. To let a function modify a caller’s variable, you pass a copy of its address (a pointer), then dereference inside the function.
Every C argument is passed by value — a copy. When you pass a pointer, you’re passing a copy of the address value, not the variable itself:
void swap(int *a, int *b) {
int t = *a; *a = *b; *b = t; // dereference to reach caller's memory
}
int x = 1, y = 2;
swap(&x, &y); // passes copies of addresses; swap modifies x,y via deref
The function can then reach into the caller’s memory through the address it received. That’s “pass by reference” in C in effect — but mechanically it’s still pass-by-value of a pointer.
(The one nuance: a const pointer int *const p would make the pointer itself immutable, but that’s separate.) The interview answer: C passes everything by value; pointers pass a copy of the address, letting functions modify caller variables via dereferencing.
3. What is the value of an uninitialized local automatic variable inside a function body?
Answer: Indeterminate (garbage) — whatever bit pattern happens to be in that stack memory; reading it before writing is undefined behavior.
Local (automatic) variables are not zero-initialized. They contain whatever leftover data occupied that stack location — stale values from previous frames. The exact content is unpredictable.
void f() {
int x; // indeterminate value
printf("%d", x); // UB: reading an uninitialized variable
}
Reading an uninitialized automatic variable is undefined behavior in C (for non-character types; even char uninitialized reads are UB before assignment in practice, though unsigned char/char are special-cased for indeterminate reads). The value is never guaranteed to be 0, NULL, or anything specific.
Contrast: static and global variables are zero-initialized. The interview answer: indeterminate garbage from the stack; reading before assignment is undefined behavior.
4. What does the enum feature in C construct?
Answer: A user-defined enumeration type: named integer constants that improve readability.
enum creates a set of named constants:
enum Color { RED, GREEN, BLUE };
enum Color c = GREEN; // c == 1
By default the constants start at 0 and increment by 1 (RED=0, GREEN=1, BLUE=2), but you can assign explicit values:
enum Status { OK = 0, ERROR = -1, TIMEOUT = 2 };
Benefits: self-documenting code (names instead of magic numbers), and the compiler can warn about unhandled cases. In C, enum values are just ints underneath — they interconvert freely with integers (unlike C++ where the rules are stricter). The interview answer: an enumeration of named integer constants for readability and type-organization.
5. What is the function of fflush(stdout)?
Answer: It forces pending buffered output in the stdout stream to be written out immediately to the terminal or file.
Standard I/O (stdio) buffers output for efficiency — printf writes into an internal buffer that’s flushed periodically (on newline for line-buffered terminals, on buffer-full, or at program exit). fflush(stdout) forces any buffered bytes out right now.
When you need it:
- Interleaving
printfwithfprintf(stderr, ...)(stderr is unbuffered, so ordering matters) — flushstdoutso the relative order is correct. - Prompting for input before reading:
printf("Enter: "); fflush(stdout);ensures the prompt appears before the user types. - Crash-prone programs: flush critical output so it survives an abnormal exit.
The interview answer: fflush(stdout) pushes buffered stdout data to the underlying output immediately.
6. What is the result of applying sizeof to a dereferenced pointer sizeof(*ptr) where double *ptr;?
Answer: The size of double — 8 bytes on standard systems.
*ptr has type double, so sizeof(*ptr) is sizeof(double) = 8 bytes. The clever part: sizeof does not evaluate its operand. It only needs the type of the expression, which is known at compile time. So ptr needn’t be initialized or even valid — sizeof(*ptr) never dereferences anything at runtime; there’s no crash.
This is a widely used idiom because it’s type-robust: sizeof(*ptr) stays correct even if you change ptr’s type. Compare sizeof(ptr) which would be the pointer size (8 on 64-bit). The interview answer: sizeof(*ptr) = sizeof(double) = 8, computed without evaluating the dereference.
7. What problem arises from using strcpy(dest, src) without prior length verification?
Answer: A buffer overflow — if src is longer than dest’s capacity, strcpy writes past the end, corrupting surrounding memory.
strcpy(dest, src) copies bytes until it hits a '\0' in src — with no bounds checking on dest. If src is longer than the destination buffer can hold:
- Bytes spill past
dest’s end into adjacent memory — other variables, saved return addresses, heap metadata. - Result: crashes, subtle data corruption, or security exploits (stack-smashing attacks that overwrite the return address).
char buf[10];
strcpy(buf, "this string is way too long"); // overflow
Safe alternatives: strncpy (bounded, but doesn’t guarantee null-termination) or better, snprintf(dest, size, "%s", src) which always null-terminates and respects the size. The interview answer: unbounded copy → stack/heap buffer overflow, memory corruption, and potential code-execution exploits.
8. What is the evaluation result of bitwise operation 5 & 3 in binary (0101 & 0011)?
Answer: 1.
Bitwise AND (&) compares bits positionally — each output bit is 1 only if both input bits are 1:
0101 (5)
& 0011 (3)
------
0001 (1)
So 5 & 3 = 1. (& is bitwise AND; don’t confuse with &&, the logical AND.) The interview answer: 0001₂ = 1.
9. What does the union structure do in C?
Answer: All members share the same memory location, sized to fit the largest member — only one member is meaningful at a time.
A union overlays all its members at the same starting address:
union Value {
int i;
float f;
char bytes[4];
};
// sizeof(union Value) == 4 (largest member)
Writing to one member overwrites the shared storage — reading a different member reinterprets those same bytes. The union is big enough for its largest member (plus alignment padding).
Use cases:
- Type punning — inspect the bytes of a
floatas anint(with care; strict aliasing rules apply, and C23’s typeof punning via unions became legal). - Memory savings — when a variable is one-of-several types, a union uses max-size instead of the sum.
- Variant/tagged structures — a union plus a discriminant
enumfield telling which member is active.
The responsibility: track which member is currently valid — there’s no automatic check. The interview answer: a single shared memory region sized for the largest member; only one field can safely hold a value at a time.
10. What is the effect of invoking abort() in a C program?
Answer: It raises SIGABRT and terminates the process immediately — without running atexit() handlers or flushing stdio buffers.
abort() (from <stdlib.h>) abnormally terminates the program:
- Raises the
SIGABRTsignal; unless caught, the process dies immediately. - Skips
atexit()cleanup handlers (the functions registered to run at normal exit). - Skips stdio buffer flushing — buffered output may be lost.
It’s the hard-kill for catastrophic/uncorrectable states where cleanup can’t be trusted. Compare exit(code), which does run atexit handlers and flushes streams before terminating normally. The interview answer: immediate SIGABRT termination, bypassing atexit handlers and stdio flushing.
Premium Content
Unlock Top 25 - Part 2 and all premium lessons with a subscription.
From ₹199.99/year — See plans