List of structs in C: solved exercise
List of structs in C: solved exercise
If you searched for a solved list of structs in C, here is the singly linked list where each node contains a Contact struct and a pointer to the next node. This pattern combines pointer management with structured data: both the struct’s dynamic fields and the node itself must be freed.
Problem statement
Define a Contact struct with fields name (32-character array), phone (16-character array), and next (pointer to the next node). Implement:
list_append(head, name, phone): inserts a node at the end.list_find(head, name): returns the pointer to the node with that name, orNULL.list_remove(head, name): deletes the node with that name.list_print(head): prints all contacts.list_free(head): frees all nodes.
C solution
Expected output
Common mistakes
- Not returning the new head when deleting the first node: if the node to delete is the head,
head = cur->nextmust be updated and the new value returned to the caller. - Freeing
curbefore savingcur->next: after freeing, accessingcur->nextis undefined behavior. - Not updating the previous node’s
nextpointer when removing: leaves a dangling pointer pointing to the freed node. - Not freeing all nodes at the end: each node was allocated with
malloc; the list must be traversed and each node freed.
Practical use
Linked lists of structs are the basic pattern of many real data structures: hash tables with chaining for collision resolution, event queues in operating systems, plugin managers that dynamically add/remove modules, and LRU caches where the oldest entry is reordered or removed.
Recommended next exercise
- qsort with structs in C: solved exercise
- Struct with pointers in C: solved exercise
- Files in C: solved exercises
- All C exercises
Guided practice and full book
If you want a complete path with progressive difficulty:
FAQ
Why do list_remove and list_append return the new head?
Because C has no references: if the head changes (first node deleted, or insertion into an empty list), the caller must receive the new pointer. The idiomatic pattern is list = list_remove(list, name).
When should a linked list be used instead of a dynamic array?
A linked list is preferable when insertions/deletions in the middle are frequent (O(1) with the pointer to the previous node) and random access is not needed. A dynamic array is better when index-based access (O(1)) is required or when contiguous memory matters for cache performance.
How do you detect memory leaks in linked lists?
With Valgrind: valgrind --leak-check=full ./program. Each node allocated with malloc that is not freed will appear as “definitely lost”. AddressSanitizer (gcc -fsanitize=address) also detects accesses to already-freed memory (use-after-free).