Placement Prep

C Programs for You: Set 3, Pointers, Recursion, and Linked Lists

Eight C programs with full solutions and output traces covering pointers, recursion, array algorithms, and linked-list operations.

By FACE Prep Team 7 min read
c-programming pointers recursion linked-lists array-algorithms placement-prep technical-interview

C placement rounds at IT companies test the same four skill categories every year: pointer operations, recursion, string manipulation, and basic data-structure logic. This set covers eight programs across all four, each with a full output trace.

What Makes C Placement Problems Different

Most placement coding platforms let candidates choose C, C++, Java, or Python. C is the tightest option: no templates, no garbage collection, no built-in containers. That constraint is why companies still use it to assess fundamentals.

The examiner is not checking whether you know every standard-library call. The real test is three things: can you manage memory manually, can you reason about pointer arithmetic, and can you design a recursive function without an obvious stack overflow. Knowing how to trace a program’s output step by step is the skill that separates candidates who get interview calls from those who do not.

Set 3 covers pointer manipulation, recursion, array and string algorithms, and linked-list operations. These four clusters appear most often across TCS, Infosys, and mid-tier IT company coding rounds.

Pointer Problems

Problem 1: Swap Two Variables Using Pointers

Passing variables by value is the most common beginner mistake in C. Swap functions only work correctly when the function receives the addresses of the two variables, not copies of their values.

#include <stdio.h>

void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main(void) {
    int x = 5, y = 10;
    printf("Before: x = %d, y = %d\n", x, y);
    swap(&x, &y);
    printf("After:  x = %d, y = %d\n", x, y);
    return 0;
}

Output:

Before: x = 5, y = 10
After:  x = 10, y = 5

The function receives &x and &y, the addresses in memory. Inside swap, the line *a = *b writes the value of y into the memory location of x. Without pointer parameters, any changes inside swap affect only local copies and the caller’s variables stay unchanged.

Problem 2: Reverse a String Using a Character Pointer

Two-pointer string reversal appears both as a standalone interview question and as a building block for palindrome checkers. C’s standard library string functions like strlen, strcpy, and strrev all work on null-terminated character arrays. Understanding the pointer mechanics behind them matters in technical interviews.

#include <stdio.h>
#include <string.h>

void reverseString(char *str) {
    char *left  = str;
    char *right = str + strlen(str) - 1;
    while (left < right) {
        char temp = *left;
        *left     = *right;
        *right    = temp;
        left++;
        right--;
    }
}

int main(void) {
    char word[] = "interview";
    printf("Original: %s\n", word);
    reverseString(word);
    printf("Reversed: %s\n", word);
    return 0;
}

Output:

Original: interview
Reversed: weivretni

left starts at index 0 ('i') and right starts at index 8 ('w'). Each iteration swaps the characters they point to, then converges the two pointers inward. The loop exits when left >= right, meaning every pair has been exchanged. This is the same two-pointer strategy used in the palindrome check article.

Recursion Problems

Problem 3: Factorial of a Number

Factorial is the standard entry point for recursion. The base case is n <= 1 (returns 1); every other call multiplies n by the result of the call with n - 1.

#include <stdio.h>

long long factorial(int n) {
    if (n <= 1) return 1;
    return n * factorial(n - 1);
}

int main(void) {
    printf("factorial(0)  = %lld\n", factorial(0));
    printf("factorial(5)  = %lld\n", factorial(5));
    printf("factorial(10) = %lld\n", factorial(10));
    return 0;
}

Output:

factorial(0)  = 1
factorial(5)  = 120
factorial(10) = 3628800

The call depth equals n. For factorial(10), the stack holds 10 activation frames before the base case fires and the returns unwind. Using long long handles results up to factorial(20) before overflow.

In interviews, state both the time complexity (O(n)) and the space complexity (O(n) call-stack depth). Interviewers routinely follow up by asking you to rewrite this iteratively, so have that version ready.

Problem 4: Count Character Occurrences Recursively

This problem combines recursion with string traversal. The function advances one character per call and adds 1 to the count when the current character matches the target.

#include <stdio.h>

int countChar(const char *str, char target) {
    if (*str == '\0') return 0;
    return (*str == target) + countChar(str + 1, target);
}

int main(void) {
    const char *msg = "banana";
    printf("'a' in \"banana\": %d\n", countChar(msg, 'a'));
    printf("'n' in \"banana\": %d\n", countChar(msg, 'n'));
    return 0;
}

Output:

'a' in "banana": 3
'n' in "banana": 2

The base case is the null terminator '\0'. The expression (*str == target) evaluates to 1 when there is a match and 0 otherwise. That value is added to the recursive count for the remaining string. “banana” has 'a' at positions 1, 3, and 5, and 'n' at positions 2 and 4. The output confirms both.

Array and String Algorithms

Problem 5: Find the Second Largest Element in an Array

Sorting and returning the penultimate element is correct but costs O(n log n). A single linear pass using two tracking variables solves the same problem in O(n) time and O(1) space. For a related single-pass scan on finding both minimum and maximum, see the min and max in an array article.

#include <stdio.h>
#include <limits.h>

int secondLargest(int arr[], int n) {
    int first = INT_MIN, second = INT_MIN;
    int i;
    for (i = 0; i < n; i++) {
        if (arr[i] > first) {
            second = first;
            first  = arr[i];
        } else if (arr[i] > second && arr[i] != first) {
            second = arr[i];
        }
    }
    return second;
}

int main(void) {
    int arr[] = {12, 35, 1, 10, 34, 1};
    int n = sizeof(arr) / sizeof(arr[0]);
    printf("Second largest: %d\n", secondLargest(arr, n));
    return 0;
}

Output:

Second largest: 34

Trace through {12, 35, 1, 10, 34, 1}:

  • After index 0: first = 12, second = INT_MIN
  • After index 1: 35 > 12 so second = 12, first = 35
  • After index 2: 1 < 35 and 1 > INT_MIN so second = 1
  • After index 3: 10 > 1 so second = 10
  • After index 4: 34 > 10 so second = 34
  • After index 5: 1 < 34 and 1 != 35 so no update

Final: second = 34

Problem 6: Concatenate Two Strings Without strcat

Writing your own string concatenation makes clear how null-terminated strings work. C’s standard library string functions, including strcat, strlen, and strcpy, all depend on a single convention: a string ends when a '\0' byte appears. Implementing that yourself makes the rule concrete.

#include <stdio.h>

void myStrcat(char *dest, const char *src) {
    while (*dest) dest++;
    while ((*dest++ = *src++));
}

int main(void) {
    char str1[20] = "hello";
    const char *str2 = " world";
    myStrcat(str1, str2);
    printf("%s\n", str1);
    return 0;
}

Output:

hello world

The first while (*dest) advances dest past the existing characters until it points to the null terminator. The second loop copies src byte by byte into dest, including the final '\0'. When '\0' is written, the assignment evaluates to 0 and the loop exits. Sizing str1 too small is the most direct path to a buffer overrun.

Linked List Operations

Problem 7: Insert a Node at the Head and Display the List

Linked list problems test struct definitions and dynamic memory allocation together. The malloc function allocates a block of memory on the heap and returns a pointer to it. Without matching free calls, that memory leaks for the lifetime of the process.

#include <stdio.h>
#include <stdlib.h>

struct Node {
    int data;
    struct Node *next;
};

struct Node *insertAtHead(struct Node *head, int val) {
    struct Node *node = malloc(sizeof(struct Node));
    node->data = val;
    node->next = head;
    return node;
}

void display(struct Node *head) {
    while (head != NULL) {
        printf("%d -> ", head->data);
        head = head->next;
    }
    printf("NULL\n");
}

int main(void) {
    struct Node *head = NULL;
    head = insertAtHead(head, 30);
    head = insertAtHead(head, 20);
    head = insertAtHead(head, 10);
    display(head);
    return 0;
}

Output:

10 -> 20 -> 30 -> NULL

Each insertAtHead call creates a new node, sets its next to the current head, and returns it as the new head. After inserting 30, then 20, then 10, the list is 10 -> 20 -> 30 -> NULL. The display function walks the chain until head == NULL. For a broader look at how data structures appear in placement rounds, see the top data-structure interview questions.

Problem 8: Detect a Cycle Using Floyd’s Algorithm

Floyd’s cycle detection is the linked-list problem interviewers use to test two-pointer thinking. A slow pointer advances one step at a time; a fast pointer advances two. If a cycle exists, the fast pointer eventually laps the slow one and they land on the same node. This runs in O(1) space compared to the hash-set alternative.

#include <stdio.h>
#include <stdlib.h>

struct Node {
    int data;
    struct Node *next;
};

int hasCycle(struct Node *head) {
    struct Node *slow = head;
    struct Node *fast = head;
    while (fast != NULL && fast->next != NULL) {
        slow = slow->next;
        fast = fast->next->next;
        if (slow == fast) return 1;
    }
    return 0;
}

int main(void) {
    struct Node *n1 = malloc(sizeof(struct Node));
    struct Node *n2 = malloc(sizeof(struct Node));
    struct Node *n3 = malloc(sizeof(struct Node));
    struct Node *n4 = malloc(sizeof(struct Node));
    n1->data = 10; n1->next = n2;
    n2->data = 20; n2->next = n3;
    n3->data = 30; n3->next = n4;
    n4->data = 40; n4->next = n2;   /* cycle: n4 points back to n2 */
    printf("Cycle detected: %s\n", hasCycle(n1) ? "Yes" : "No");
    return 0;
}

Output:

Cycle detected: Yes

Pointer trace for the list 10 -> 20 -> 30 -> 40 -> (back to 20):

  • Iteration 1: slow = n2, fast = n3
  • Iteration 2: slow = n3, fast = n2 (fast jumped n3 to n4 to n2)
  • Iteration 3: slow = n4, fast = n4 (fast jumped n2 to n3 to n4)

slow == fast on iteration 3 confirms the cycle.

What to Practice Next

The eight programs above cover the C fundamentals that recruiters test in the first technical round. The next layer is harder variations: reversing a linked list in groups, finding the middle node in one pass (also two pointers), and writing a binary search using recursion. For problems that combine string logic with tight index constraints, the flower-sticks arrangement problem is good practice in boundary thinking.

The data-structure interview questions guide covers the full range from stacks to graphs; it’s a useful reference once the eight programs here feel routine.

Writing recursive solutions from scratch and tracing pointer semantics step by step are the same mental habits that make debugging multi-step API calls tractable. TinkerLLM is a ₹299 entry point where you can apply that same trace-and-verify discipline to real LLM API problems. Apply the same step-by-step trace to a prompt chain that you applied to Floyd’s algorithm above.

Primary sources

Frequently asked questions

What does *ptr mean in C and how is it different from &var?

The * operator dereferences a pointer — *ptr reads or writes the value at the address stored in ptr. The & operator takes the address of a variable — &var returns the memory location of var. The two are inverses of each other.

How do I trace a recursive call stack on paper in an interview?

Draw a call column going down to the base case, then write return values back up. For factorial(4): calls descend 4 then 3 then 2 then 1; returns come back 1 then 2 then 6 then 24.

What is Floyd's cycle detection algorithm in a linked list?

Floyd's algorithm uses a slow pointer that moves one step at a time and a fast pointer that moves two steps. If a cycle exists, the fast pointer eventually catches up to the slow one and they point to the same node. If no cycle exists, the fast pointer reaches NULL first.

Is sorting a valid approach for finding the second largest element in an array?

Sorting is correct but runs in O(n log n) time. A single-pass approach using two tracking variables runs in O(n) time and O(1) space. In a placement interview, mention both and prefer the O(n) solution — it shows you think about efficiency.

Can I use gets() in C placement coding tests in 2026?

Avoid gets(). It was removed from the C11 standard because it has no bounds checking and causes buffer overflows. Use fgets(str, sizeof(str), stdin) instead. Most 2026 placement compilers will warn or reject gets() outright.

Do linked list programs appear in off-campus placement coding tests?

Yes. Linked list insert, delete, reverse, and cycle detection are standard in TCS Digital, Infosys SE, and most product-company coding rounds. Floyd's cycle detection is especially common because it demonstrates two-pointer thinking.

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