Interview questions

C Linked List Interviews: The Pointer Playbook

July 4, 2025Updated May 20, 202618 min read
Are You Underestimating The Power Of C Linked List In Interviews

A C-first guide to linked list interviews: node structs, head updates, insert/delete/reverse/merge patterns, fast-slow pointers, cycle removal, and the edge.

Linked list questions look simple on paper right up until you have to move pointers in C and narrate every step out loud. That's where C linked list interviews actually get decided — not on whether you know what a linked list is, but on whether you can trace a pointer reassignment without losing the rest of the list, explain why you're freeing memory in that order, and handle the empty-list case before the interviewer has to ask. Most candidates can name the patterns. Far fewer can execute them cleanly in C without a garbage collector catching their mistakes.

The good news is that the surface area is smaller than it looks. Reverse, insert, delete, merge, cycle detection, and two-pointer tricks cover the overwhelming majority of what shows up. If you understand the pointer mechanics behind those operations — not just the code, but why each pointer gets saved before it gets overwritten — you can answer most linked list questions in C with genuine confidence rather than rehearsed fragments.

Start With the One C Representation You'll Actually Use

Every linked list problem in C starts from the same struct. Getting comfortable with it — really comfortable, not just able to recite it — is the foundation for everything else. C linked list interviews test this representation implicitly in every question.

A node is just data, a next pointer, and ownership you can explain

The canonical node looks like this:

That's it. Two fields. The complexity lives entirely in how you manage the `next` pointer and who is responsible for the memory behind it. In a garbage-collected language, ownership is someone else's problem. In C, every `malloc` needs a matching `free`, and every insert or delete decision is also a memory decision. If you allocate a new node inside an insert function, you need to be clear — to yourself and to the interviewer — about whether the caller owns that node or the list does. Getting that wrong doesn't just fail the test case; it produces a memory leak or a double-free that a production code reviewer would flag immediately.

When you allocate a node, check the return value:

That null check isn't ceremonial. Interviewers who care about C correctness will notice if you skip it.

What singly, doubly, and circular lists change in the code

A singly linked list gives you one pointer per node: `next`. You can traverse forward and you can insert or delete in O(1) if you already have the predecessor, but you cannot walk backward. A doubly linked list adds a `prev` pointer, which makes backward traversal and O(1) deletion without a predecessor possible, at the cost of maintaining two pointers on every operation. A circular list — singly or doubly — replaces the terminal `NULL` with a pointer back to the head, which changes every traversal termination condition from `curr != NULL` to `curr != head`.

The concrete case where doubly linked deletion changes meaningfully: if you have a pointer directly to the node to delete (no predecessor given), a singly linked list forces you to traverse from the head to find the previous node. A doubly linked list lets you do it in place:

Both `prev` and `next` need maintenance. Missing either one corrupts the list. According to MIT OpenCourseWare's data structures materials, the defining property of a doubly linked list is precisely that bidirectional pointer maintenance — it's not a performance optimization, it's a structural guarantee.

Why lists beat arrays in some interview problems and lose in others

Arrays are the right answer for random access, cache locality, and problems where you know the size upfront. A dynamic array with amortized O(1) append beats a linked list on most real workloads. Steelmanning the array answer is important because interviewers sometimes want to hear that you know the tradeoff, not just that you reached for the list.

The real reason linked lists win in interview problems is cheap rewiring when you already have the node. Inserting into the middle of an array requires shifting every subsequent element. Inserting between two linked list nodes requires updating two pointers. That's it. When the problem involves frequent insertion or deletion at arbitrary positions — and when you already have the predecessor node — the list wins cleanly. Not because it's magically faster everywhere, but because the operation cost is localized.

Insert and Delete Without Losing the Head

The most common mistake in insert and delete isn't a logic error — it's a pointer ordering error. You overwrite a pointer before saving what it pointed to, and you've just lost the rest of the list. Linked list pointers in C don't have undo.

Insert at the head, tail, and middle without breaking the chain

Insert at the head: save the new node's next pointer first, then update the head. Never the other way around.

If you write `*head = new_node` first, you've lost the original head and can't set `new_node->next` correctly. This is the lost-head bug in its simplest form. It's embarrassingly easy to write, and embarrassingly easy to prevent if you think about the order before you type.

Insert at the tail: traverse to the last node (the one where `next == NULL`), then set its `next` to the new node. The new node's `next` stays `NULL`.

Insert in the middle: find the predecessor, save `predecessor->next`, set `new_node->next = predecessor->next`, then set `predecessor->next = new_node`. That sequence is non-negotiable. Reversing the last two steps skips every node after the insertion point.

Delete the node and free it, not the whole list by accident

The safe delete sequence in C is: unlink first, free second. Never free a node while you still need to read its `next` pointer.

For deleting a middle node given a pointer to its predecessor:

The null assignment after free is defensive practice. It won't save you if another pointer still references the freed node, but it prevents the most naive dangling-pointer use from silently succeeding. If you're deleting the head, the caller's `head` pointer must also be updated — which is why head-update functions in C should take `Node *head`, not `Node head`.

The dummy-node trick makes the awkward cases behave

A dummy node is an empty sentinel node whose `next` points to the real head. You never return the dummy; you return `dummy->next` at the end. Its only job is to make the "update the head" case look identical to every other case.

Without a dummy node, deleting the first node that matches a value requires a special branch. With a dummy node:

No special case for the head. The dummy absorbs it. This pattern comes up in merge, delete-all-matching-values, and partition problems — any time head updates would otherwise create branching logic that's easy to get wrong under pressure. The CLRS textbook uses sentinel nodes precisely for this reason: they simplify boundary conditions without changing the algorithm's correctness.

Reverse and Merge by Rewiring, Not by Memorising

Reversal and merge are two of the most common linked list interview questions in C. The mistake most people make is memorizing the code without understanding the pointer sequence — which means the first follow-up question breaks them.

Reverse one node at a time and keep three pointers straight

You need three pointers: `prev` (starts NULL), `curr` (starts at head), and `next` (temporary). The loop body is always the same four steps:

Trace it on a three-node list: A→B→C→NULL.

  • Iteration 1: save B, point A→NULL, prev=A, curr=B
  • Iteration 2: save C, point B→A, prev=B, curr=C
  • Iteration 3: save NULL, point C→B, prev=C, curr=NULL
  • Loop ends. Return C. List is now C→B→A→NULL.

Every pointer gets saved before it gets overwritten. That's the invariant. If you can say that out loud while drawing it, you've answered the follow-up before it's asked.

Merge two sorted lists with the dummy-node pattern

Merging two sorted lists is a pointer race. At each step, you pick the smaller head, attach it to your result, and advance that list's pointer. The dummy node handles the "where does the result list start" problem cleanly.

When one list runs out, you don't need to copy the rest — you just point `tail->next` at whatever remains. No allocation, no free, just a pointer update. The dummy node means you never need a special case for the very first node appended to the result.

What to say when the interviewer asks why your rewrite is safe

The explanation matters as much as the code. For reversal: "I save `curr->next` before overwriting `curr->next` because once I reverse the link, I have no way to reach the rest of the list. `prev` tracks where I've been, `curr` tracks where I am, `next_node` is the only reference to where I'm going." For merge: "I'm not allocating any new nodes — I'm rewiring existing ones. The dummy node gives me a stable attachment point so I don't have to handle the first-node case separately. When the loop ends, the remaining sublist is already linked correctly, so I just attach it."

That kind of explanation — ownership, invariant, termination — is what separates a candidate who understands the code from one who memorized it.

Use Fast and Slow Pointers When the List Hides a Shape

Two-pointer techniques solve a family of C linked list problems that share a common structure: the list has a shape property (length, midpoint, cycle) that you need to find without extra storage. These are the core C linked list problems where pointer spacing does the measurement work.

Middle node and kth from end are the same trick in disguise

For the middle node, `slow` moves one step and `fast` moves two. When `fast` reaches the end, `slow` is at the middle.

For kth from end, advance `fast` exactly k steps first. Then move both pointers one step at a time until `fast` reaches NULL. `slow` is now at the kth node from the end. The spacing between the pointers — k steps — is what does the work. You're not counting from the end; you're maintaining a fixed gap from the front.

Detect a cycle before it turns into an infinite loop

Floyd's cycle detection uses the same slow/fast structure. If there's a cycle, fast will eventually lap slow and they'll meet inside it. If there's no cycle, fast reaches NULL.

The concrete failure case this prevents: if you try to traverse or print a cyclic list without detection, you loop forever. If you try to free a cyclic list, you'll either hang or double-free nodes. According to Knuth's *The Art of Computer Programming*, Floyd's algorithm is the canonical O(1)-space cycle detection method — it's worth knowing the name and the reasoning, not just the code.

Find the intersection or merge point without counting nodes

Two lists that share a tail have a merge point. The trick: advance each pointer to the end of its list, then restart it at the head of the other list. After at most `len(A) + len(B)` steps, both pointers have traveled the same total distance and will meet at the merge point — or both reach NULL if there's no intersection.

No extra storage, no counting nodes upfront. The path equalization is the entire algorithm. If you can draw it — two paths of different lengths, both pointers crossing over — you can explain it under pressure.

Remove a Cycle Without Making the Damage Worse

Detecting a cycle and removing it are different operations. Conflating them is the structural bug that corrupts the list. Linked list pointers in C give you no safety net once a node's `next` points somewhere it shouldn't.

Find the loop entry point before you touch anything else

After Floyd's detection confirms a cycle (slow and fast have met), reset one pointer to the head. Move both pointers one step at a time. They meet again at the loop entry node. Don't touch any links until you've found this node — any premature rewiring while you're still inside the cycle risks losing nodes or creating a new corruption.

Cut the cycle cleanly and prove the list is still intact

Once you know the entry node, traverse the cycle to find the last node (the one whose `next` points back to the entry). Set its `next` to NULL:

After this, the list terminates normally. Every node before the entry is untouched. Every node in the former cycle is still reachable from the entry. Nothing is lost, nothing is freed prematurely.

What goes wrong when you free or traverse in the wrong order

Once a list loops, naïve traversal never terminates — `curr != NULL` is never true. A naïve free loop will free the same nodes repeatedly once it cycles back, producing undefined behavior. The structural bug isn't carelessness; it's that the standard termination condition is simply wrong for a cyclic list. Detecting the cycle before traversal or freeing isn't optional hygiene — it's the only way to make those operations correct.

Know the Bug Traps Before the Interview Finds Them for You

The bugs that fail C linked list interviews aren't exotic. They're the same four mistakes, repeated across different problems.

The boring bugs are the ones that fail your answer

  • Lost head: you overwrote `head` or a predecessor's `next` before saving the pointer you needed. The rest of the list is now unreachable.
  • Skipped node: you updated `curr->next` before setting `new_node->next`, so the node that was at `curr->next` is now orphaned.
  • Null dereference: you accessed `curr->next->data` without checking that `curr->next` is not NULL. This crashes. Always check before dereferencing.
  • Double free: you freed a node through one pointer and then freed it again through another. This is undefined behavior, and in a cyclic list it's easy to trigger without noticing.

The fix for all four is the same discipline: write the pointer order down before you write the code, and check every pointer before you dereference it.

Edge cases should be your first test, not your afterthought

Before you say your solution is correct, run it mentally against: empty list (`head == NULL`), one-node list, deleting the head node, deleting the tail node, all nodes having the same value (for delete-all-matching), and a list of length two (which often breaks reversal or merge logic that assumes at least three nodes). These aren't adversarial inputs — they're the first thing a careful interviewer will try. Naming them yourself, before being asked, signals that you think about correctness structurally rather than reactively.

How to talk through correctness when the room is silent

When you finish writing the code and the interviewer is quiet, don't wait. Say the invariant: "At every step of the loop, `prev` holds the already-reversed portion and `curr` holds the unreversed portion — and I never move `curr` until I've saved its `next`." Say the termination condition: "The loop exits when `curr` is NULL, which means every node has been processed." Say the ownership: "I'm not allocating any new nodes, so there's nothing to free." Three sentences. That's the whole explanation. It's not elaborate — it's just the thing that proves you understand what you wrote.

How Verve AI Can Help You Ace Your Backend Coding Interview

The sequences that matter most in a backend coding interview — "explain why you saved that pointer before overwriting it," "what happens if the list is empty," "walk me through the cycle removal" — only get comfortable with practice that responds to what you actually said, not a fixed set of model answers. That's the structural gap most prep tools don't close.

Verve AI Interview Copilot is built for exactly this: it listens in real-time to your answer, understands the specific claim you just made, and responds to the follow-up that your answer actually invites — not a canned next question. If you explain the reversal loop correctly but gloss over the termination condition, Verve AI Interview Copilot will surface that gap the way a real interviewer would. If you miss the null check on a delete operation, it catches it. The practice loop is tight because the feedback is specific to your words, not to a template answer.

For C pointer work in particular — where the interviewer is listening for ownership language, pointer order justification, and edge-case awareness — Verve AI Interview Copilot lets you rehearse under live pressure without needing a human interviewer available. It runs on desktop and browser, stays invisible during the session, and covers the full range of backend and systems interview topics. The single capability that changes the calculus for this kind of prep: Verve AI Interview Copilot can probe your explanation, not just your code, which is where C linked list interviews are actually won or lost.

FAQ

Q: What are the core linked list concepts I need to explain clearly in a C interview?

Node structure and ownership (`malloc`/`free`), pointer rewiring order for insert and delete, head updates via double pointers (`Node **`), and termination conditions for traversal. If you can explain why each pointer is saved before it's overwritten, you've covered the conceptual ground that most C-specific questions probe.

Q: How do I implement insert, delete, reverse, and merge safely with C pointers and head updates?

For insert and delete: always save the pointer you're about to overwrite before you overwrite it, unlink before freeing, and use `Node **head` when the head might change. For reverse: maintain `prev`, `curr`, and a saved `next` — never overwrite `curr->next` without saving it first. For merge: use a dummy node so the first-node case is handled identically to every other case.

Q: What are the most common linked list interview patterns: fast/slow pointers, dummy nodes, and in-place rewiring?

Fast/slow pointers solve middle-node, kth-from-end, cycle detection, and merge-point problems. Dummy nodes simplify delete-matching and merge by eliminating head-update special cases. In-place rewiring — changing `next` pointers without allocating new nodes — is the core technique for reverse, merge, and cycle removal. These three patterns, combined, cover the majority of what appears in C linked list interviews.

Q: How do I detect and remove a cycle in C without losing nodes or dereferencing null pointers?

Detect with Floyd's algorithm (slow/fast pointers meet inside the cycle). Find the entry by resetting one pointer to head and walking both one step at a time until they meet again. Remove by traversing the cycle to find the last node and setting its `next` to NULL. Never touch links during detection — only after the entry node is confirmed.

Q: How do I solve middle-node, kth-from-end, and merge-point problems in a way I can explain under interview pressure?

Middle: slow moves one step, fast moves two — when fast reaches the end, slow is at the middle. Kth from end: advance fast k steps, then move both until fast is NULL — the spacing does the counting. Merge point: restart each pointer at the other list's head when it reaches NULL — path equalization brings them to the intersection. In each case, the explanation is the spacing or path property, not the code mechanics.

Q: What edge cases should I test for singly and doubly linked lists before I say my solution is correct?

Empty list, single-node list, two-node list, deleting the head, deleting the tail, all-duplicate values for delete-all-matching, and a list where the answer is the last node (for kth-from-end or merge). For doubly linked lists, also test that both `prev` and `next` are correctly maintained when deleting the first or last node.

Q: Which linked-list questions are most likely to appear for a backend software engineer interviewing in C?

Reverse a singly linked list, detect and remove a cycle, merge two sorted lists, find the middle node, delete the nth node from the end, and detect a list intersection. These cover the structural operations — reversal, merging, two-pointer traversal — that backend interviews use to test whether a candidate understands memory ownership and pointer correctness in a language without a garbage collector.

Conclusion

Pointer manipulation in C isn't inherently hard — it's just unforgiving. Every mistake is permanent until you explicitly fix it, and the interview room doesn't give you a debugger. But that also means the skill is learnable and finite: if you can trace a reversal, explain a dummy-node merge, and articulate why you saved `curr->next` before overwriting it, you've covered the mechanical core of most linked list questions you'll face.

Before your next interview, take one operation — reversal, or delete-with-dummy — and draw it by hand on paper. Not pseudocode, not a mental model: actual boxes for nodes, arrows for pointers, and a step-by-step trace of every pointer move. If you can draw it without getting lost, you can explain it without getting lost. That's the whole game.

JM

James Miller

Career Coach

Ace your live interviews with AI support!

Get Started For Free

Available on Mac, Windows and iPhone