Introduction
In our last lesson, we built the essential functions for populating a linked list, allowing us to add new items to our game inventory at the beginning, at the end, or in sorted order. With a list full of items, the next logical steps are to find specific items and remove them. This lesson completes the core set of operations on our data structure by focusing on precisely that: searching for and deleting nodes.
You will learn to implement functions to locate a node by its value and then safely remove it from the list, regardless of its position. Mastering this is crucial for managing a dynamic inventory, where items are constantly being acquired, used, or dropped. We'll pay close attention to pointer manipulation and memory management, building directly on the concepts of traversal and double pointers from our previous session.
Searching a Linked List
Before we can delete an item by its value (e.g., removing a "Health Potion"), we must first find it. The process of searching a linked list is a fundamental traversal algorithm. You start at the head and move from node to node until you either find the value you're looking for or reach the end of the list (NULL).
The logic is simple:
- Create a temporary pointer,
current, and initialize it to the head of the list. - Loop as long as
currentis notNULL. - Inside the loop, check if the data in the
currentnode matches the key you're searching for. - If it's a match, the search is successful. You can return a pointer to the node or simply a
truevalue. - If it's not a match, advance to the next node:
current = current->next. - If the loop completes without finding the key, the search fails, and you can return
NULLorfalse.
The following resource provides a complete, professional C implementation of this logic.
Linked List Operations: Traverse, Insert and Delete
This article from Programiz contains a full C code example for various linked list operations. We will focus on the searchNode function.
Within the C code block, locate the function int searchNode(struct Node** head_ref, int key). Study this function to see the traversal algorithm in action. Note how it returns 1 for success and 0 for failure. This function is a concise implementation of the search logic.
Deleting a Node from a Linked List
Deleting a node is more intricate than insertion because you must correctly "un-wire" the node from the list before freeing its memory. A mistake here can either break the chain or, worse, create a memory leak.
There are three main scenarios to consider when deleting a node, which are expertly outlined in the following video.
How to Delete a Node in a Linked List by Searching for a Value
This video from Gina Sprint provides a fantastic overview of the deletion process, breaking it down into manageable cases.
Please watch the introduction from the beginning to the three cases. This will give you a clear mental map of the problem: handling an empty list, deleting the head, and deleting a node from the middle or end.
Let's examine these cases one by one.
Case 1: Deleting the Head Node
This is a critical special case. If the item to be deleted is the very first one in our inventory, we must update the list's head pointer. As you'll recall from our previous lesson on insertion, any function that might change the head of the list needs access to the original head pointer. This is where using a double pointer (struct Node **head_ref) is essential.
The algorithm is:
- Check if the list is non-empty and if the head node contains the value to be deleted.
- Create a temporary pointer (
temp) to hold the current head node. - Update the list's head to point to the next node (
*head_ref = temp->next). - Free the memory of the original head node using the temporary pointer (
free(temp)).

Case 2: Deleting a Node in the Middle or at the End
This is the general case. To remove a node from the middle or end of the list, you need to find it, but you also need to modify the next pointer of the node before it. This requires keeping track of two pointers as you traverse: a current pointer and a previous pointer.
The algorithm is:
- Initialize
currentto the head of the list andprevioustoNULL. - Traverse the list, advancing both pointers (
previous = current; current = current->next;) until you find the node to delete or reach the end. - If the node is found (
current != NULL), you "splice" it out by linking the previous node to the current node's successor:previous->next = current->next. - Finally,
free(current)to release its memory.
This two-pointer traversal technique is a cornerstone of linked list manipulation. The following video segment provides an excellent trace of this exact process.
How to Delete a Node in a Linked List by Searching for a Value
Let's return to Gina Sprint's video to see a walkthrough of the prev/cur pointer technique for deleting a node from the middle.
Watch the segment from the main algorithm. Pay close attention to how the prev and cur pointers advance and how the link is re-established once the target node is found.
A Complete Implementation
Now, let's combine these cases into a single, robust deleteNode function. The code will first check the head case, and if that doesn't apply, it will proceed with the prev/cur traversal to handle the middle/end case.
The Programiz article you reviewed for searching also provides an excellent C implementation for deletion.
Linked List Operations: Traverse, Insert and Delete
Let's look at the complete deleteNode function from the same Programiz C code block.
Find and study the function void deleteNode(struct Node** head_ref, int key). Trace its logic: The head deletion case, which handles removing the first node. The traversal loop, which uses prev and temp (our current) pointers. The final steps, which handle the case where the key is not found, or perform the splice-and-free operation.
To see this code built from scratch and tested, you can also watch the coding portion of Gina Sprint's video.
How to Delete a Node in a Linked List by Searching for a Value
This part of the video translates the algorithm we've discussed into a complete C function and tests it.
You can watch the section from coding it up to see the if-else structure that handles the head vs. middle cases. The following segment, testing the code, is also valuable as it demonstrates the function's correctness with various scenarios.
An Alternative Approach: The "Look-Ahead"
The prev/cur pointer method is very common, but there is another valid technique that uses only one traversal pointer. This method involves "looking ahead" to the next node's value.
The logic is as follows:
- Handle the head deletion as a separate special case.
- For the general case, start a
currentpointer at the head. - Loop while
current->nextis notNULL. - In the loop, check if
current->next->datais the value to be deleted. - If it is, you've found the node before the one to delete. You can then perform the splice:
- Save the node to delete:
node_to_delete = current->next. - Rewire the link:
current->next = node_to_delete->next. - Free the memory:
free(node_to_delete).
- Save the node to delete:
This approach is conceptually interesting and is demonstrated well in the following video.
Removing an element from a linked list
This video from CodeVault illustrates the "look-ahead" technique for deletion.
First, watch the visual explanation from the visual concept. Then, see the code implementation in the segment from the code walkthrough. Notice how this implementation must still handle deleting the root as a separate case before the main loop (the root case).
While both the prev/cur and "look-ahead" methods work, many programmers find the prev/cur pattern slightly more straightforward, as the main loop's logic directly operates on the current node rather than its successor.
Conclusion
You have now completed the fundamental set of linked list manipulations: insertion, searching, and deletion. With these tools, your linked list is no longer just a static chain but a fully dynamic data structure capable of managing the contents of a game inventory.
Key Takeaways:
- Searching is a basic traversal that moves from node to node until a match is found or the list ends.
- Deletion must handle three distinct cases: an empty list, removing the head node, and removing a node from the middle or end.
- Deleting the head is a special case that requires updating the list's main
headpointer, making a double pointer (**head_ref) the ideal tool. - Deleting from the middle/end is typically handled with a
previousandcurrenttwo-pointer traversal to allow for the "splicing" of the node out of the list. - Memory management is non-negotiable: you must always call
free()on the deleted node's memory to prevent memory leaks.
In our next lesson, we will address the final piece of the puzzle: safely destroying an entire linked list. You will write a function that traverses the whole list and deallocates every single node, ensuring our program is clean and leak-free when an inventory is no longer needed.