For working professionals
For fresh graduates
More
5. Array in C
13. Boolean in C
18. Operators in C
33. Comments in C
38. Constants in C
41. Data Types in C
49. Double In C
58. For Loop in C
60. Functions in C
70. Identifiers in C
81. Linked list in C
83. Macros in C
86. Nested Loop in C
97. Pseudo-Code In C
100. Recursion in C
103. Square Root in C
104. Stack in C
106. Static function in C
107. Stdio.h in C
108. Storage Classes in C
109. strcat() in C
110. Strcmp in C
111. Strcpy in C
114. String Length in C
115. String Pointer in C
116. strlen() in C
117. Structures in C
119. Switch Case in C
120. C Ternary Operator
121. Tokens in C
125. Type Casting in C
126. Types of Error in C
127. Unary Operator in C
128. Use of C Language
When debugging programs in C, especially those that rely heavily on arrays, beginners often hit a wall. Static memory allocation, fixed sizes, and inflexible data movement limit what you can do. That’s where the linked list in C comes into play.
Unlike arrays, this structure allows dynamic memory handling, smoother insertions, and deletions — all without the struggle of shifting elements or predicting memory needs. Whether you’re building a basic student record system or managing memory blocks manually, a linked list unlocks capabilities that arrays can't handle with ease.You can also explore our in-depth Software engineering courses to deepen your understanding of such concepts.
In this article, we’ll walk through every aspect of using a linked list in C — from its core types and structure to creation, operations, and performance insights. You’ll also see where it's most useful, and where it might let you down.
In C programming, managing data dynamically is often necessary when working with unpredictable input sizes. While arrays allocate a fixed memory block, linked lists provide a flexible alternative. A linked list in C is a linear data structure where elements are stored in nodes. Each node contains two parts — the data and a pointer to the next node.
This structure is not stored contiguously in memory. Instead, each node can reside anywhere in memory, with pointers maintaining the chain. The first node is known as the head. The last node points to NULL, marking the end of the list.
Here’s a basic node declaration in C:
struct Node {
int data;
struct Node* next;
};
You create each node dynamically using malloc(), making it ideal for situations where memory use needs to scale during runtime.
Take your AI and Data Science skills to the next level with these top programs:
A linked list in C provides flexibility that arrays can’t match. Here's why it’s often a better choice:
In C, linked lists come in several forms. Each type suits a different set of use cases. Understanding them helps you choose the right structure for your problem.
Here are the major types of linked list in C:
Each node contains:
Traversal is possible in one direction only — from head to NULL.
Example:
struct Node {
int data;
struct Node* next;
};
Use case: Simple, linear data flow (e.g., student records, task lists)
To read in depth, check out the Understanding Singly Linked Lists: A Comprehensive Guide!
Each node contains:
Traversal is possible in both directions — forward and backward.
Example:
struct Node {
int data;
struct Node* prev;
struct Node* next;
};
Use case: Navigating both ways in a music playlist or browser history
To read in depth, check out the Doubly Linked List Implementation in C and Java: A Comprehensive Guide
Similar to a singly linked list, but the last node points back to the first node, forming a circle.
Example:
struct Node {
int data;
struct Node* next;
};
Note: The next pointer of the last node points to the head.
Use case: Round-robin schedulers, circular buffers
To read in depth, check out the Circular Linked Lists in Action: A Programmer's Guide
This is a doubly linked list where the next pointer of the last node points to the head, and the prev pointer of the head points to the last node.
Example:
struct Node {
int data;
struct Node* prev;
struct Node* next;
};
Use case: Multiplayer game turns, cyclic queues
To explore in-depth, read the circular doubly linked list article!
This version includes a special header node at the beginning of the list. Unlike regular nodes, the header node does not hold actual data. It acts as a placeholder or control point for easier list management — especially useful for simplifying edge-case operations like insertion at the beginning.
Structure:
struct Node {
int data;
struct Node* next;
};
In this case, the first node (header) often contains default or dummy values, and the actual list starts from header->next.
Use case:Used in implementations where operations like deletion, insertion, or traversal need a consistent starting point, reducing code complexity.
Each of these types offers a balance between traversal capabilities and memory usage. The choice depends on whether you need bidirectional movement, circular references, or a simple linear chain.
Discover how to build a stack using a linked list in C.
In C, a linked list is built using structures and pointers. Each node is defined as a structure that contains two parts:
This design allows dynamic connections between elements, without needing contiguous memory like arrays.
Basic Structure of a Node
Here’s how you define a node in a singly linked list in C:
struct Node {
int data;
struct Node* next;
};
The last node’s next pointer is set to NULL.
Head Pointer
The starting point of any linked list is the head — a pointer to the first node:
struct Node* head = NULL;
If the list is empty, the head remains NULL.
Memory Allocation
You create nodes dynamically using malloc():
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = 10;
newNode->next = NULL;Each new node is linked to the previous one by assigning the next pointer.
Example: Creating a Two-Node List
struct Node* head = (struct Node*)malloc(sizeof(struct Node));
head->data = 5;
struct Node* second = (struct Node*)malloc(sizeof(struct Node));
second->data = 10;
head->next = second;
second->next = NULL;
This creates a simple chain: *[5 | ] → [10 | NULL]
The same logic extends to doubly and circular linked lists — the only difference lies in the number and behavior of pointers.
Check out how to implement a queue using a linked list in C
Creating a linked list in C involves dynamically allocating memory for each node and connecting them using pointers. Here's a step-by-step guide to help you build a simple singly linked list.
1. Define the Node Structure
The first step is defining the structure for a node. Each node will contain:
struct Node {
int data;
struct Node* next;
};
2. Create a New Node
To add a new node, we use malloc() to allocate memory. This ensures that each node gets its own memory space, and we can add as many nodes as needed.
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = 10; // Set data for the new node
newNode->next = NULL; // This will be the last node, so next is NULL
3. Link the Nodes Together
After creating the first node (called the head), the next step is to link it to the second node. The next pointer of the first node will point to the second node.
struct Node* head = newNode; // Head now points to the first node
struct Node* secondNode = (struct Node*)malloc(sizeof(struct Node));
secondNode->data = 20;
secondNode->next = NULL; // The second node's next pointer is NULL
head->next = secondNode; // The first node points to the second node
Now, we have a simple linked list with two nodes: [10 | *] → [20 | NULL].
4. Insert a Node at the Beginning
Inserting a node at the start requires creating a new node and adjusting the pointers so that the new node becomes the head:
struct Node* newHead = (struct Node*)malloc(sizeof(struct Node));
newHead->data = 5;
newHead->next = head; // Point newHead to the previous head
head = newHead; // Update head to point to the new node
Now, the list looks like: **[5 | ] → [10 | ] → [20 | NULL]
5. Traverse the List
To print or access all nodes in a linked list, you traverse from the head node and follow the next pointers until you reach NULL:
struct Node* temp = head;
while (temp != NULL) {
printf("%d -> ", temp->data);
temp = temp->next;
}
Output:
5 -> 10 -> 20 -> NULL
6. Freeing the List
To prevent memory leaks, always free the memory allocated for each node once you’re done with the list:
free(newNode);
free(secondNode);
free(newHead);
Linked lists offer better memory utilization by dynamically allocating memory as required. For a deeper understanding of dynamic memory allocation in C, read this article.
The power of a linked list in C lies in its flexible operations. You can insert, delete, search, and update elements dynamically — without worrying about memory size constraints like arrays. Here's a breakdown of the essential operations:
You can insert nodes at:
Example: Insert at the beginning
void insertAtBeginning(struct Node** head, int data) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = *head;
*head = newNode;
}
You can delete a node from:
Example: Delete first node
void deleteFirst(struct Node** head) {
if (*head == NULL) return;
struct Node* temp = *head;
*head = (*head)->next;
free(temp);
}
To process or print all nodes:
void traverse(struct Node* head) {
while (head != NULL) {
printf("%d -> ", head->data);
head = head->next;
}
}
Search for a specific value in the list:
int search(struct Node* head, int key) {
while (head != NULL) {
if (head->data == key) return 1;
head = head->next;
}
return 0;
}
To count the total number of elements:
int countNodes(struct Node* head) {
int count = 0;
while (head != NULL) {
count++;
head = head->next;
}
return count;
}
Reverse the linked list in-place:
void reverse(struct Node** head) {
struct Node* prev = NULL;
struct Node* current = *head;
struct Node* next = NULL;
while (current != NULL) {
next = current->next;
current->next = prev;
prev = current;
current = next;
}
*head = prev;
}
Each operation gives you more control over dynamic data structures. With a proper grasp of these, you can build more complex ADTs like stacks, queues, and graphs. If you're unfamiliar with C functions, explore this guide to learn more.
Traversal is one of the most fundamental operations in a linked list in C. It means visiting each node in the list — usually to display, search, or process its data. Traversing efficiently helps keep your program fast and memory-safe.
Step-by-Step Traversal Approach
Example: Traverse and Print
void printList(struct Node* head) {
while (head != NULL) {
printf("%d -> ", head->data);
head = head->next;
}
printf("NULL\n");
}
This code prints each value in the list, ending with NULL.
Output Example:
5 -> 10 -> 20 -> NULL
Avoid Common Mistakes
When Traversal Becomes Costly
Traversing a linked list takes O(n) time. In long lists, repeated traversals (like for every insertion or deletion at the end) can slow down performance. Use pointers to the tail or caching when needed.
Traversing with Conditions
You can also traverse conditionally, for example, to find all nodes with even data:
void printEvenNodes(struct Node* head) {
while (head != NULL) {
if (head->data % 2 == 0)
printf("%d ", head->data);
head = head->next;
}
}
Efficient traversal comes down to clean logic and pointer safety. It’s the gateway to mastering other list operations.
Must Explore: Data Structures in C
A linked list in C isn’t just an academic concept — it powers real-world systems that need dynamic memory and flexible data management. Its pointer-based structure makes it ideal for situations where arrays fall short.
Here are common and practical uses:
Dynamic Memory-Based Structures
File Management Systems
Undo/Redo Functionality
Text editors and IDEs maintain a history using doubly linked lists. Each action points to previous and next states.
Memory Management in OS
Operating systems use linked lists for:
Music and Video Playlists
Circular linked lists let you cycle through tracks infinitely — ideal for media players.
Graph Representations
Adjacency lists in graphs are implemented using arrays of linked lists — especially effective in sparse graphs.
Simulation and Real-Time Applications
Linked lists handle real-time jobs (like in printers or traffic signal systems) where jobs/tasks are dynamically added or removed.
Polynomial and Big Integer Arithmetic
Each term or digit is stored as a node, making it easy to perform operations like addition, multiplication, etc., without memory limits.
These applications prove that linked lists are not just theoretical but form the backbone of flexible data modeling in software.
Advantages | Disadvantages |
Grows and shrinks dynamically at runtime | No direct access to elements (linear search required) |
Insertions and deletions are efficient, especially at the beginning or middle | Each node needs extra memory for a pointer |
Allocates memory as needed — no over-allocation | Pointer handling makes code more complex |
Suitable for implementing complex structures like stacks, queues, and graphs | Nodes are scattered in memory — cache performance drops |
Makes better use of heap memory (compared to arrays using stack) | Reverse traversal in singly linked list is hard |
Can be extended into circular or doubly linked lists | More prone to bugs due to manual pointer manipulation |
Do check out: Array in C
Understanding the time and space complexity of a linked list in C helps in analyzing its performance. Let’s break it down based on common operations:
Operation | Singly Linked List | Doubly Linked List |
Traversal | O(n) | O(n) |
Insertion at Beginning | O(1) | O(1) |
Insertion at End | O(n)* | O(1)** |
Deletion at Beginning | O(1) | O(1) |
Deletion at End | O(n) | O(1)** |
Insertion in Middle | O(n) | O(n) |
Deletion in Middle | O(n) | O(n) |
Extra space is used for storing pointers, unlike arrays.
Aspect | Array | Linked List |
Access | O(1) | O(n) |
Insertion/Deletion | O(n) | O(1) ifpositionisknownif position is knownifpositionisknown |
Space Flexibility | Fixed | Dynamic |
Knowing these complexities helps you choose the right data structure depending on the task — whether speed, memory efficiency, or ease of use is the priority.
A linked list in C provides a flexible and efficient way to manage dynamic data. Unlike arrays, it doesn't require a predefined size and allows quick insertions and deletions — making it ideal for real-world applications like memory management, queues, file systems, and graph representations.
You've seen its core types, how it's implemented, and the key operations it supports. While linked lists come with trade-offs like extra memory use and slower access times, they shine in situations where data structure flexibility is critical.
If you're building a system that involves frequent data changes or uncertain sizes, linked lists offer a clear advantage. And as a beginner, mastering this foundational structure will sharpen your pointer skills and deepen your understanding of how memory works in C.
A linked list in C is a dynamic data structure where each node contains data and a pointer to the next node. Unlike arrays, linked lists don't require predefined sizes and allow efficient insertions and deletions.
Linked lists allocate memory at runtime, allowing the structure to grow or shrink as needed. This flexibility prevents memory wastage and adapts well to varying data sizes.
In linked lists, adding or removing nodes involves updating pointers, eliminating the need to shift elements as in arrays. This results in faster operations, especially at the beginning or middle of the list.
Linked lists have slower access times due to sequential traversal, increased memory usage from storing pointers, and more complex pointer management compared to arrays.
Linked lists lack direct indexing; to access an element, you must traverse from the head node to the desired position, leading to O(n) time complexity for access operations.
Each node in a linked list contains a pointer to the next node. Managing these pointers requires careful handling to avoid issues like memory leaks or dangling pointers, making implementation more complex.
The main types include singly linked lists (each node points to the next), doubly linked lists (nodes have pointers to both next and previous nodes), and circular linked lists (the last node points back to the first).
Arrays are preferable when you need constant-time access to elements via indexing and when the number of elements is known and fixed, as they offer better cache performance and simpler implementation.
Yes, linked lists serve as the foundation for various data structures like stacks, queues, and graphs, providing dynamic memory management and efficient insertion/deletion operations.
A header linked list includes a dummy node at the beginning, simplifying insertion and deletion operations by reducing edge cases, especially when modifying the first node.
In a doubly linked list, each node has pointers to both its next and previous nodes, allowing traversal in both directions and facilitating operations like reverse traversal more efficiently.
Each node in a linked list requires additional memory to store pointers, leading to higher memory consumption compared to arrays, especially in large datasets.
Linked lists store nodes in non-contiguous memory locations, resulting in poor spatial locality. This leads to more cache misses during traversal, affecting performance negatively.
Yes, in a circular linked list, the last node points back to the first node, forming a loop. This structure is useful in applications like round-robin scheduling or buffering.
Linked lists offer O(1) time complexity for insertions and deletions at the beginning but O(n) for access and search operations. Arrays provide O(1) access time but O(n) for insertions and deletions.
Take a Free C Programming Quiz
Answer quick questions and assess your C programming knowledge
Author
Start Learning For Free
Explore Our Free Software Tutorials and Elevate your Career.
Talk to our experts. We are available 7 days a week, 9 AM to 12 AM (midnight)
Indian Nationals
1800 210 2020
Foreign Nationals
+918068792934
1.The above statistics depend on various factors and individual results may vary. Past performance is no guarantee of future results.
2.The student assumes full responsibility for all expenses associated with visas, travel, & related costs. upGrad does not provide any a.