
Before starting to implement linked list in C, let’s see what self-referential structures are. Also, you need to know about dynamic memory allocation, which you can find here in this link. For example, let’s define a structure like below:
struct node {
int data;
struct node *nextPtr;
}; // end struct node
In the above struct node, we have two members, viz. integer member data and pointer member nextPtr. Also, the pointer points to same type struct node, hence the name self-referential structure. Moreover, it is also called a link.
Linked List in C
A linked list is a linear collection of self-referential structures, called nodes, connected by pointer links. That is why, the term ’linked’ list. We can access a linked list via a pointer to the first node of the list. On the other hand, we access the subsequent nodes via the link pointer member which we store in each node. Finally, by convention, we set the link pointer in the last node to NULL to mark the end of the list. Also, we store the data dynamically in a linked list. Furthermore, a node can contain data of any type including other structs.
Implementation Example
Now, we are going to implement linked list in C, which stores a character in an alphabetical order.
#include <stdio.h>
#include <stdlib.h>
// Self-referential Structure
struct listNode {
char data; // A character data in the list
struct listNode *nextPtr; // Pointer to next node
}; // end struct listNode
typedef struct listNode ListNode; // alias for the struct
typedef ListNode *ListNodePtr; // alias for ListNode*
// Declarations
void insert(ListNodePtr *sPtr, char value);
char delete(ListNodePtr *sPtr, char value);
int isEmpty(ListNodePtr sptr); // Memory!
void showList(ListNodePtr currentPtr);
void showMenu(void);
int main() {
// Initially, there are no nodes
ListNodePtr startPtr = NULL;
// User's choice
unsigned int ch;
// User's entered character
char item;
// Display the menu
showMenu();
printf("? ");
scanf("%u", &ch);
// Loop unless user chooses 3
while(ch != 3) {
switch(ch) {
case 1:
printf("Enter a character: ");
scanf("\n%c", &item);
// insert the item in list
insert(&startPtr, item);
showList(startPtr);
break;
case 2:
// if list is not empty
if(!isEmpty(startPtr)) {
printf("Enter character to be deleted: ");
scanf("\n%c", &item);
// Remove the character if found
if (delete(&startPtr, item)) {
printf("%c deleted.\n", item);
showList(startPtr);
}
else {
printf("%c not found. \n\n", item);
}
}
else {
printf("The list is empty. \n");
}
break;
default:
printf("Invalid choice.\n");
showMenu();
break;
}
showMenu();
printf("? ");
scanf("%u", &ch);
}
printf("Thank You!\n");
return 0;
}
// Display Menu Function
void showMenu(void) {
printf("Enter your choice:\n"
" 1 to insert element into the list.\n"
" 2 to delete element from the list.\n"
" 3 to end" );
}
// insert a new value into the list in sorted order
void insert(ListNodePtr *sPtr, char value) {
ListNodePtr newPtr; // pointer to new node
ListNodePtr previousPtr; // pointer to previous node
ListNodePtr currentPtr; // pointer to current node
newPtr = malloc(sizeof(ListNode)); // Create a node
// if allocated
if (newPtr != NULL) {
newPtr->data = value; // put value in the node
newPtr->nextPtr = NULL; // doesn't have to link to another node
previousPtr = NULL;
currentPtr = *sPtr;
// find the correct location in the list
while(currentPtr != NULL && value > currentPtr->data) {
previousPtr = currentPtr;
currentPtr = currentPtr->nextPtr;
}
// insert new node at beginning of list
if (previousPtr == NULL) {
newPtr->nextPtr = *sPtr;
*sPtr = newPtr;
}
else {
previousPtr->nextPtr = newPtr;
newPtr->nextPtr = currentPtr;
}
}
else {
printf("%c is not inserted. \n", value);
}
}
// delete a list element
char delete(ListNodePtr *sPtr, char value) {
ListNodePtr previousPtr;
ListNodePtr currentPtr;
ListNodePtr tmpPtr;
// delete first node
if (value == (*sPtr)->data) {
tmpPtr = *sPtr; // hold onto node being removed
*sPtr = (*sPtr)->nextPtr; // de-thread the node
free(tmpPtr); // free the de-threaded node
return value;
}
else {
previousPtr = *sPtr;
currentPtr = (*sPtr)->nextPtr;
// find the correct location in the list
while (currentPtr != NULL && currentPtr->data != value) {
previousPtr = currentPtr;
currentPtr = currentPtr->nextPtr;
}
// delete node at currentPtr
if (currentPtr != NULL) {
tmpPtr = currentPtr;
previousPtr->nextPtr = currentPtr->nextPtr;
free(tmpPtr);
return value;
}
}
return '\0'; // NULL
}
// return 1 if the list is empty, otherwise 0
int isEmpty(ListNodePtr sPtr) {
return sPtr == NULL;
}
// show the list
void showList(ListNodePtr currentPtr) {
// if list is empty
if (isEmpty(currentPtr)) {
printf("The list is empty!\n");
}
else {
printf("The list is: \n");
// while not the end of list
while(currentPtr != NULL) {
printf("%c ==> ", currentPtr->data);
currentPtr = currentPtr->nextPtr;
}
printf("NULL\n");
}
}
In the above example, we saw how we can perform insert and delete operations in linked list. It is all explained in the comments in the program. In a nutshell, you have to create a new node and point to its address from previous node. On the other hand, while deleting, you have to delete the node and set the nextPtr of previous node to NULL.
You can view the the code in the gist here.