C programming forms the basis of technical interviews at many companies. Interviewers often ask tricky C questions to evaluate a candidate’s understanding of core concepts like pointers, memory management, and flow control. Mastering such questions is key to successfully clearing coding interviews of C.
Why Tricky Questions Matter in C Programming Interviews
Tricky questions in C help assess a candidate’s:
- Depth of knowledge in C
- Ability to analyze and solve problems
- Understanding of edge cases and nuances
- Experience debugging complex scenarios
This article of mostly asked interview questions of C will equip you with techniques to tackle such questions and explain the thought process behind arriving at solutions.
Tricky Question 1: Pointers and Arrays in C
The Mystery of Pointer Arithmetic
Pointers and arrays in C have an intimate relationship. Pointer arithmetic in C allows accessing array elements efficiently. But it can also lead to confusing edge cases.
Question 1.1: Swapping Two Integers Using Pointers
Problem: Write a code snippet to swap two integer variables, a and b, using pointer arithmetic.
Question 1.2: Finding the Largest Element in an Array Using Pointers
Problem: Given an integer array arr of size n, find the largest element in the array using pointer arithmetic.
Solution and Explanation
// Swapping two integers using pointers
#include <stdio.h>
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int a = 10, b = 20;
swap(&a, &b);
printf("a = %d, b = %d", a, b);
return 0;
}
// Output
a = 20, b = 10
// Finding the largest element using pointers
#include <stdio.h>
int findLargest(int* arr, int n) {
int max = *arr; // assume first element is largest initially
for(int i=1; i<n; i++) {
if(*(arr + i) > max) {
max = *(arr + i);
}
}
return max;
}
int main() {
int arr[] = {25, 78, 49, 45, 63};
int n = sizeof(arr)/sizeof(arr[0]);
int largest = findLargest(arr, n);
printf("Largest element is: %d", largest);
return 0;
}
// Output
Largest element is: 78
Tricky Question 2: Memory Allocation in C
Navigating Dynamic Memory Allocation in C
Dynamic allocation with malloc()/free() allows flexible memory management. But when used incorrectly, it can lead to bugs.
Question 2.1: Implementing a Custom Memory Allocator
Problem: Write a custom memory allocator my_malloc() to allocate requested memory dynamically.
Question 2.2: Detecting Memory Leaks in C Programs
Problem: Given a C program, identify potential memory leaks caused by incorrect memory management.
Solution and Explanation
// Custom memory allocator
#include <stdio.h>
#include <stdlib.h>
void* my_malloc(size_t size) {
void* ptr = malloc(size);
if(!ptr) {
printf("Memory allocation failed\n");
return NULL;
}
return ptr;
}
int main() {
int* ptr = (int*)my_malloc(sizeof(int));
if(ptr) {
*ptr = 100;
printf("Value at ptr = %d", *ptr);
}
return 0;
}
// Output
Value at ptr = 100
For question 2.2, examine the code for mismatches between malloc() and free() calls. Also, ensure all allocated memory is freed before program termination to prevent leaks.
Tricky Question 3: Recursion in C
The Depth of Recursion in C
Recursion allows elegant solutions but can also lead to stack overflows if not written carefully.
Question 3.1: Calculating Fibonacci Numbers Efficiently
Problem: Write a recursive C function to calculate the nth Fibonacci number efficiently.
Question 3.2: Implementing a Recursive Binary Search
Problem: Implement a recursive binary search algorithm on a sorted integer array.
Solution and Explanation
// Efficient Fibonacci using recursion
int fib(int n) {
if (n == 0 || n == 1) {
return n;
}
int a = 0, b = 1, c, i;
for(i = 2; i <= n; i++) {
c = a + b;
a = b;
b = c;
}
return b;
}
// Uses iteration to avoid exponential recursion tree of naive solution.
// Recursive binary search
int binarySearch(int arr[], int l, int r, int x) {
if (r >= l) {
int mid = l + (r - l) / 2;
if (arr[mid] == x) {
return mid;
}
if (arr[mid] > x) {
return binarySearch(arr, l, mid - 1, x);
}
return binarySearch(arr, mid + 1, r, x);
}
return -1;
}
// Recursion reduces code complexity compared to iterative solutions.
Recursion elegantly solves problems like Fibonacci and Binary Search. Care must be taken to avoid costly repeated function calls.
Tricky Question 4: Preprocessor Directives in C
Unraveling the Power of Macros
Preprocessor macros enable metaprogramming but can also lead to unexpected outcomes.
Question 4.1: Creating a Custom ASSERT Macro
Problem: Implement a C macro ASSERT() for debugging that prints an error and exits if the condition is false.
Question 4.2: Conditional Compilation with Macros
Problem: Use preprocessor directives for conditional debugging and logging.
Solution and Explanation
// Custom ASSERT macro
#include <stdio.h>
#define ASSERT(condition, err_msg) \
if(!(condition)) { \
fprintf(stderr, "Assertion failed: %s\n", err_msg); \
exit(1); \
}
int main() {
int x = 5, y = 10;
ASSERT(x == y, "x is not equal to y");
printf("Code after ASSERT\n"); // Will not print
return 0;
}
Macros replace code at the preprocessing stage. This allows the implementation of language extensions like ASSERT.
For question 4.2, use #ifdef DEBUG … #endif to conditionally execute debugging/logging code only in debug builds.
Tricky Question 5: if-else Statements in C
Question 5.1: Printing a Name Without Using a Semicolon
Problem: Print your name using if-else statements without ending the statement with a semicolon.
Question 5.2: Predicting the Output of Complex If/Else Statement
Problem: To print numbers from 1 to 100, create a C program. Print “Fizz” instead of the number for multiples of 3 and “Buzz” for multiples of 5. Print “FizzBuzz” for values that are multiples of both 3 and 5.
Solution and Explanation
// Print name without semicolon
#include <stdio.h>
int main() {
if(1)
if(1)
printf("John");
else
printf("Doe");
return 0;
}
// Nested ifs allow printing without a semicolon.
#include <stdio.h>
int main() {
for(int i=1; i<=100; i++) {
if(i%3 == 0 && i%5 == 0) {
printf("FizzBuzz\n");
}
else if(i%3 == 0) {
printf("Fizz\n");
}
else if(i%5 == 0) {
printf("Buzz\n");
}
else {
printf("%d\n", i);
}
}
return 0;
}
//Output
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
…
…
Buzz
97
98
Fizz
Buzz
Tricky Question 6: Increment and Decrement Operators in C
Question 6.1: Evaluating Expression x = 5; y = x++ + ++x – –x + x–
Problem: Determine the value of x and y after the given expression.
Question 6.2: Predicting the Output of Complex Increment/Decrement Sequences
Problem: Given the following code snippet, predict the final values of x and y:
int x = 5, y = 10; x++; y--; ++x; --y; x++; y--;
Solution and Explanation
For 6.1, x = 5 originally. Expression is evaluated as:
y = 5 + 7 - 6 + 5 = 11 x = 5
For 6.2, Let’s evaluate the code step-by-step:
Initial values: x = 5, y = 10 x++; // x = 6 y--; // y = 9 ++x; // x = 7 (pre-increment) --y; // y = 8 (pre-decrement) x++; // x = 8 (post-increment) y--; // y = 7 (post-decrement) Therefore, final values after complete execution are: x = 8 y = 7
The key things to notice are:
Difference between pre and post-increment/decrement
Order in which each statement is executed
Conclusion
Mastering tricky C programming interview questions is a vital skill for acing interviews. This article covered key problem areas like pointers, memory allocation, recursion, data structures, and increment/decrement operators. Analyzing edge cases, understanding nuances, and tracing logical flow are crucial. With rigorous preparation on such questions, you can demonstrate comprehensive C programming knowledge. Practice problems hone the analytical abilities needed for software roles. Strive to write clean, readable code. Mastering core concepts will open up exciting career opportunities.
