C course menu
C Coding Interview Challenges with Solutions
Classic C coding interview problems with full, tested solutions and complexity analysis: reverse a string in place, implement strcpy and atoi, find duplicates, remove duplicates from a sorted array, second largest element, reverse a linked list, detect a cycle, rotate an array, binary search, and count words.
On this page
- Challenge 1: Reverse a string in place
- Challenge 2: Implement strcpy and strcat
- Challenge 3: Implement atoi
- Challenge 4: Find the first repeated character
- Challenge 5: Remove duplicates from a sorted array
- Challenge 6: Second largest element
- Challenge 7: Rotate an array to the right by k
- Challenge 8: Reverse a linked list
- Challenge 9: Detect a cycle in a linked list
- Challenge 10: Count words in a sentence
- How to approach a coding interview in C
These problems are favourites in C interviews because they test pointers, strings and memory together. For each one, think about edge cases (empty input, one element, NULL) and state the time and space complexity before you open the solution.
Challenge 1: Reverse a string in place#
Reverse a string without using another array.
Show solution
Swap characters from both ends, moving towards the middle. O(n) time, O(1) extra space.
#include <stdio.h>
#include <string.h>
void reverse(char *s) {
if (s == NULL) return;
size_t n = strlen(s);
if (n < 2) return;
for (char *l = s, *r = s + n - 1; l < r; l++, r--) {
char t = *l;
*l = *r;
*r = t;
}
}
int main(void) {
char a[] = "interview";
char b[] = "";
reverse(a);
reverse(b);
printf("[%s] [%s]\n", a, b);
return 0;
}[weivretni] []Challenge 2: Implement strcpy and strcat#
Show solution
#include <stdio.h>
char *my_strcpy(char *dst, const char *src) {
char *start = dst;
while ((*dst++ = *src++) != '\0') { }
return start;
}
char *my_strcat(char *dst, const char *src) {
char *p = dst;
while (*p) p++; /* find the end of dst */
my_strcpy(p, src);
return dst;
}
int main(void) {
char buf[32];
my_strcpy(buf, "embedded");
my_strcat(buf, " systems");
printf("%s\n", buf);
return 0;
}embedded systemsMention that, like the standard versions, these assume the destination is big enough, which is why snprintf is safer in real code.
Challenge 3: Implement atoi#
Convert a string to an int: skip leading spaces, handle an optional sign, stop at the first non-digit, and clamp to INT_MAX/INT_MIN on overflow.
Show solution
Check for overflow before multiplying, so no signed overflow ever happens. O(n) time.
#include <limits.h>
#include <stdio.h>
int my_atoi(const char *s) {
while (*s == ' ' || *s == '\t') s++;
int sign = 1;
if (*s == '+' || *s == '-') {
if (*s == '-') sign = -1;
s++;
}
int result = 0;
while (*s >= '0' && *s <= '9') {
int digit = *s - '0';
if (result > (INT_MAX - digit) / 10) {
return sign == 1 ? INT_MAX : INT_MIN;
}
result = result * 10 + digit;
s++;
}
return sign * result;
}
int main(void) {
const char *tests[] = {"42", " -17abc", "+0", "99999999999", "-2147483648", "abc"};
for (int i = 0; i < 6; i++) printf("\"%s\" -> %d\n", tests[i], my_atoi(tests[i]));
return 0;
}"42" -> 42
" -17abc" -> -17
"+0" -> 0
"99999999999" -> 2147483647
"-2147483648" -> -2147483648
"abc" -> 0-2147483648 clamps to INT_MIN, which happens to be the right value: its magnitude does not fit in a positive int.
Challenge 4: Find the first repeated character#
Return the first character in a string that appears again later, or '\0' if none repeats.
Show solution
A 256-entry table of "seen" flags gives O(n) time and O(1) space (the table size does not depend on the input):
#include <stdio.h>
char first_repeat(const char *s) {
unsigned char seen[256] = {0};
for (; *s; s++) {
unsigned char c = (unsigned char)*s;
if (seen[c]) return *s;
seen[c] = 1;
}
return '\0';
}
int main(void) {
const char *tests[] = {"programming", "abcdef", "abca"};
for (int i = 0; i < 3; i++) {
char c = first_repeat(tests[i]);
printf("%s: %c\n", tests[i], c ? c : '-');
}
return 0;
}programming: r
abcdef: -
abca: aChallenge 5: Remove duplicates from a sorted array#
Remove duplicates in place and return the new length.
Show solution
Two indexes: write marks the end of the unique part. O(n) time, O(1) space.
#include <stdio.h>
int dedupe(int *a, int n) {
if (n == 0) return 0;
int write = 1;
for (int read = 1; read < n; read++) {
if (a[read] != a[write - 1]) a[write++] = a[read];
}
return write;
}
int main(void) {
int a[] = {1, 1, 2, 3, 3, 3, 7, 9, 9};
int n = dedupe(a, 9);
for (int i = 0; i < n; i++) printf("%d ", a[i]);
printf("(length %d)\n", n);
return 0;
}1 2 3 7 9 (length 5)Challenge 6: Second largest element#
Find the second largest distinct value in one pass.
Show solution
#include <limits.h>
#include <stdio.h>
int second_largest(const int *a, int n, int *out) {
int first = INT_MIN, second = INT_MIN, found = 0;
for (int i = 0; i < n; i++) {
if (a[i] > first) {
second = first;
first = a[i];
} else if (a[i] < first && a[i] > second) {
second = a[i];
}
}
for (int i = 0; i < n; i++) if (a[i] == second && second < first) found = 1;
if (found) *out = second;
return found;
}
int main(void) {
int a[] = {12, 35, 1, 10, 34, 35};
int b[] = {5, 5, 5};
int r;
if (second_largest(a, 6, &r)) printf("%d\n", r);
printf("%s\n", second_largest(b, 3, &r) ? "found" : "no second largest");
return 0;
}34
no second largestThe found check handles arrays where every value is the same, and arrays that contain INT_MIN itself.
Challenge 7: Rotate an array to the right by k#
Show solution
The reversal trick: reverse the whole array, then reverse the first k and the rest. O(n) time, O(1) space.
#include <stdio.h>
static void rev(int *a, int i, int j) {
while (i < j) {
int t = a[i];
a[i++] = a[j];
a[j--] = t;
}
}
void rotate_right(int *a, int n, int k) {
if (n == 0) return;
k %= n;
rev(a, 0, n - 1);
rev(a, 0, k - 1);
rev(a, k, n - 1);
}
int main(void) {
int a[] = {1, 2, 3, 4, 5, 6, 7};
rotate_right(a, 7, 3);
for (int i = 0; i < 7; i++) printf("%d ", a[i]);
printf("\n");
return 0;
}5 6 7 1 2 3 4 Challenge 8: Reverse a linked list#
Show solution
Iteratively turn each next pointer around. O(n) time, O(1) space.
#include <stdio.h>
#include <stdlib.h>
typedef struct Node { int v; struct Node *next; } Node;
Node *push(Node *head, int v) {
Node *n = malloc(sizeof *n);
if (n == NULL) exit(1);
n->v = v;
n->next = head;
return n;
}
Node *reverse(Node *head) {
Node *prev = NULL;
while (head) {
Node *next = head->next;
head->next = prev;
prev = head;
head = next;
}
return prev;
}
void print(const Node *p) {
for (; p; p = p->next) printf("%d ", p->v);
printf("\n");
}
int main(void) {
Node *list = NULL;
for (int i = 5; i >= 1; i--) list = push(list, i);
print(list);
list = reverse(list);
print(list);
while (list) { Node *n = list->next; free(list); list = n; }
return 0;
}1 2 3 4 5
5 4 3 2 1 Challenge 9: Detect a cycle in a linked list#
Show solution
Floyd's "tortoise and hare": a slow pointer moves one node at a time and a fast one moves two. If there is a cycle they meet; otherwise the fast pointer reaches NULL. O(n) time, O(1) space.
#include <stdio.h>
typedef struct Node { int v; struct Node *next; } Node;
int has_cycle(const Node *head) {
const Node *slow = head, *fast = head;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) return 1;
}
return 0;
}
int main(void) {
Node n[4];
for (int i = 0; i < 4; i++) { n[i].v = i; n[i].next = (i < 3) ? &n[i + 1] : NULL; }
printf("%d\n", has_cycle(&n[0]));
n[3].next = &n[1]; /* create a cycle: 3 -> 1 */
printf("%d\n", has_cycle(&n[0]));
return 0;
}0
1Challenge 10: Count words in a sentence#
Count words separated by any amount of whitespace.
Show solution
Count the transitions from "outside a word" to "inside a word". O(n) time.
#include <ctype.h>
#include <stdio.h>
int count_words(const char *s) {
int count = 0, in_word = 0;
for (; *s; s++) {
if (isspace((unsigned char)*s)) {
in_word = 0;
} else if (!in_word) {
in_word = 1;
count++;
}
}
return count;
}
int main(void) {
printf("%d\n", count_words(" C is a small\tlanguage \n"));
printf("%d\n", count_words(""));
return 0;
}5
0How to approach a coding interview in C#
- Clarify the input: can it be empty or
NULL? What are the limits? - Explain your approach and its complexity before writing code.
- Write small helper functions with clear names; check every
malloc. - Test out loud with a normal case and edge cases (empty, one element, duplicates, overflow).
- Free what you allocate, and mention what you would improve with more time.
Finished this lesson?