Reuseable linked list implementation - c

Hi I'm trying to implement a generic linked list. I've got something working using the following code but I can't see an obvious and neat way to remove the dependance on the global pointers (curr and root,) and thus allow multiple linked lists to be defined. If I were using c++ I would probably just wrap the whole thing in a class, but as it is I can only see one solution which is manually handling and passing root and curr to the functions that need them. I'm sure there is a better way than this so how would you go about this.
Thanks
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
struct Node{
int value;
struct Node *next;
};
struct Node * curr = NULL;
struct Node * root = NULL;
struct Node * createList(int val){
struct Node *n = malloc(sizeof(struct Node));
if(n==NULL){
printf("Node creation failed\n");
return NULL;
}
n->value = val;
n->next = NULL;
root=curr=n;
return n;
}
struct Node * extendList(int val, bool end){
if(curr == NULL){
return createList(val);
}
struct Node * newNode = malloc(sizeof(struct Node));
if(newNode==NULL){
printf("Node creation failed\n");
return NULL;
}
newNode->value = val;
newNode->next = NULL;
if(end){
curr->next = newNode;
curr = newNode;
}
else{
newNode->next = root;
root=newNode;
}
return curr;
}
void printList(void){
struct Node *ptr = root;
while(ptr!=NULL){
printf("%d\n",ptr->value);
ptr = ptr->next;
}
return;
}
struct Node * pos_in_list(unsigned int pos, struct Node **prev){
struct Node * ptr = root;
struct Node * tmp = NULL;
unsigned int i = 0;
while(ptr!=NULL){
if(i == pos){
break;
}
tmp = ptr;
ptr=ptr->next;
i++;
}
*prev = tmp;
return ptr;
}
void deletefromlist(int pos){
struct Node * del = NULL;
struct Node * prev = NULL;
del = pos_in_list(pos,&prev);
if(del == NULL)
{
printf("Out of range\n");
}
else
{
if(prev != NULL)
prev->next = del->next;
if(del == curr)
{
curr = prev;
}
else if(del == root)
{
root = del->next;
}
}
free(del);
del = NULL;
}
void deleteList(){
struct Node * del = root;
while(curr!=NULL){
curr = del->next;
free(del);
del=curr;
}
root = NULL;
curr = NULL;
}
int main(void)
{
int i;
for(i=0;i<10;i++){
extendList(i,true);
}
for(i=10;i>0;i--){
extendList(i,false);
}
printList();
deletefromlist(5);
printList();
deleteList();
return 0;
}

Create a Structure of Node * root and Node * curr
struct LinkedList{
struct Node * curr;
struct Node * next;
};

You can create another struct to hold the curr and root. This struct will function like a "linked-list object" frontend, while your node structs will be the backend. As an added benefit, you can store other attributes about the linked-list, like the number of elements in the list.
struct LinkedList {
int numElements;
struct Node * curr;
struct Node * root;
};
You can modify your functions to work with this struct, and once you are done, the benefit is that the end-user can create many linked-lists, and all they have to do is call the functions and pass in their pointers to the LinkedList struct.

The way this is usually done is by giving each function an argument for the linked list pointer. Like this:
struct Node * extendList(struct Node * head, int val, bool end){
if(head == NULL){
return createList(val);
}
struct Node * newNode = malloc(sizeof(struct Node));
if(newNode==NULL){
printf("Node creation failed\n");
return NULL;
}
newNode->value = val;
newNode->next = NULL;
struct Node * tail = head;
while (tail->next) tail = tail->next;
tail->next = newNode;
tail = newNode;
return newNode; // return the new node
}
Which removes any need for a global pointer and allows for an arbitrary number of lists. In fact, I would strongly advise you to avoid the use of global variables in this context.
I had submitted a review for a linked list implementation you can check out. You may want to check the criticisms to, the ones that may apply to your own implementation.

I have implemented a generic list in C.
It is intended to be used as a static library. List operations (on generic data) are exposed from a list service. As you have asked,
neat way to remove the dependance on the global pointers (head)
Defining multiple linked lists.
This list service accomplish both these features in following way,
Upon creating a new Linked list this service returns a unique identifier representing it instead of traditional Linked list head pointer. This way client code can't directly corrupt linked list. this list service allows creation of multiple linked lists. Each having unique id. It is upto client to free lists when they are done and service can re-use that slot later when creating a new one. Maintaining global head pointer for each list is mandatory in any approach, but here is it hidden inside list service.
Following is my implementation :
https://github.com/rajan-goswami/glist/wiki

Take a look at the Berkeley-derived generic implementations for some other ideas on how to do it.
Documentation queue(3)
Source OpenBSD, Linux libc

Related

How to access linked list node from other function?

Hey im trying to make a linked list. I created linked list from other function called CreateLibrary. but then how can I access the head of the node of the linked list from other function?
int *HeadGlobal;
struct node {
char judul[50], author[30];
struct node *link;
};
int CreateLibrary(struct node *head) {
struct node *head = malloc(sizeof(struct node));
HeadGlobal = head;
}
int ViewData() {
char judul[50], author[50];
struct node *head = malloc(sizeof(struct node));
head = &HeadGlobal;
printf("%s dan %s", head->judul, head->author);
}
I tried to make HeadGlobal Pointer and save the head pointer into this global pointer, therefore accessing it from other function,called ViewData(). but I think its not the correct solution. how to solve this?
The name CreateLibrary implies that you should be able to create any number of libraries. You do not need any global variables to achieve that. You are also confusing the type needed to maintain a library. Your linked list should maintain a linked list of struct nodes - not ints.
Here's an example of how that may look:
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct node node; // makes it possible to use `node` instead of `struct node`
struct node {
char judul[50], author[30];
node *link;
};
typedef struct {
node* head;
node* tail;
size_t count;
} library; // library is the type maintaining info about one library instance
// here's the function to create one instance of a library:
library *CreateLibrary() {
library *newlibrary = malloc(sizeof *newlibrary);
if(newlibrary == NULL) return newlibrary;
// initialize this new empty library:
newlibrary->head = NULL;
newlibrary->tail = NULL;
newlibrary->count = 0;
return newlibrary;
}
// a function to clean up:
void DestroyLibrary(library *lib) {
for(node *curr = lib->head, *next; curr != NULL; curr = next) {
next = curr->link;
free(curr);
}
free(lib);
}
// a helper function to create a new node:
node *CreateNode(const char *judul, const char *author) {
node *new_node = malloc(sizeof *new_node);
if(new_node == NULL) return new_node; // oups - this should rarely happen
new_node->link = NULL;
// copy the supplied information into the new node:
strncpy(new_node->judul, judul, sizeof new_node->judul);
new_node->judul[sizeof new_node->judul - 1] = '\0'; // just a precaution
strncpy(new_node->author, author, sizeof new_node->author);
new_node->author[sizeof new_node->author - 1] = '\0'; // just a precaution
return new_node;
}
// a helper function to add a node to the library:
bool AddToLibrary(library *lib, node *new_node) {
if(new_node == NULL) return false; // we won't add node pointers pointing at NULL
if(lib->head == NULL) { // this is the first node added to library
lib->head = new_node;
} else { // there is already at least one node in the library
lib->tail->link = new_node;
}
lib->tail = new_node; // and the new node is the new tail
lib->count++; // increase the number of nodes in the library
return true; // we successfully added the node
}
// print the information about one specific node:
void ViewNode(const node *node) {
printf("%s dan %s\n", node->judul, node->author);
}
// print the information for all nodes in one specific library:
void ViewLibrary(const library *lib) {
for(node *curr = lib->head; curr != NULL; curr = curr->link) {
ViewNode(curr);
}
}
Example usage:
int main() {
library *lib = CreateLibrary();
if(lib == NULL) return 1; // failure :-(
AddToLibrary(lib, CreateNode("foo", "Hello"));
AddToLibrary(lib, CreateNode("bar", "World"));
ViewLibrary(lib);
DestroyLibrary(lib);
}
Demo

How do I delete an entire circular linked list in C?

I am having a problem with the free() function of C's stdlib, of my knowladge this function can only delete a given node of the linked list at a time, how can i use this function to delete an entire circular linked list ?
Do I have to make a pointer pointing to the head of the circular linked list and beguin to free node by node with the care to make each pointer from one node tho the next, be taken to point to NULL before i can free that node ? and if so how do I free the head node ?
You could theoretically, re-alloc the whole heap memory of a list and pass it to a free function.
However the most secure way to clean up a linked list is to iterate and free , each node.
This is an example of a destructor function.
void destroy_link_list(linked_list_t** link_list)
{
node_t* head = (*link_list)->start_node;
while(head != NULL)
{
node_t* temp = head->next;
free(head->data_list);
head->data_list = NULL;
free(head);
head = temp;
}
(*link_list)->start_node = NULL;
free(*link_list);
*link_list = NULL;
}
This linked list looks like this
typedef struct node node_t;
struct node
{
int unique_id;
node_t* next;
void* data_list;
};
typedef struct linked_list
{
int num_nodes;
node_t* start_node;
}linked_list_t;
So this is how to delete an entire Circular Linked List:
node* clear(node *n){
if (n->next == head){
free(n);
n = NULL;
return n;
}
n->next = clear(n->next);
free(n);
n = NULL;
return n;
}
Call function as:
head = clear(head);
Why does this not work ?
void freePolinomial(Polinomial p){
Polinomial before, after;
after = p -> aft;
do{
before = after;
after = after->aft;
before->aft = NULL;
free(before);
}while(after != NULL && (after->index) != -1);
p=NULL;
after->aft = NULL;
free(after);
}
where each node has an index and the head node has -1 as an index.

Is this a proper implementation of a DeleteList function? [LINKED LIST via heaps]

I must write a function DeleteList() that takes a list, deallocates all of its memory and sets its head pointer to NULL (the empty list).
It seems to work, but idk if it truly works because the way in which I implemented (which I assume is the wrong way) is very different than the one in the solution. I assume it only deletes a few nodes or there is an issue with the memory management.
int Length(struct node* head)
{
int count = 0;
struct node* current = head;
while (current != NULL)
{
count++;
current = current->next;
}
return(count);
}
void DeleteList(struct node** headRef)
{
int len = Length(*headRef);
for(int i = 0;i<len;i++)
free(*headRef);
*headRef = NULL;
}
You are not actually freeing the whole linked list but you are freeing head node repeatedly. I would suggest you to use below approach.
void DeleteList(struct node** headRef) {
struct node *ptr = *headRef;
struct node *temp = NULL;
while(ptr)
{
temp = ptr;
ptr = ptr->next;
free(temp);
}
*headRef = NULL;
}

How to modularize a Linked List?

I have the following Linked List:
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data; // Linked List type of data.
struct Node *next; // Pointer to the next Node.
};
void printfList(struct Node *head)
{
while(head != NULL)
{
printf(" %d\n", head -> data);
head = head -> next;
}
}
int main()
{
struct Node *head = NULL;
struct Node *second = NULL;
struct Node *third = NULL;
head = (struct Node*) malloc(sizeof(struct Node));
second = (struct Node*) malloc(sizeof(struct Node));
third = (struct Node*) malloc(sizeof(struct Node));
head -> data = 1;
head -> next = second;
second -> data = 2;
second -> next = third;
third -> data = 3;
third -> next = NULL;
printfList(head);
return 0;
}
How can I modularize this example to get something more professional? node type and separated from the others and function separately?
I think by "modularize" here you mean more kinda professional, clean looking code, I came up with following :
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data; // Linked List type of data.
struct Node *next; // Pointer to the next Node.
};
struct Node * makeNode(int data){
struct Node *temp = (struct Node*)malloc(sizeof(struct Node));
temp->data = data;
temp->next = NULL;
return temp;
}
void printfList(struct Node *head)
{
while(head != NULL)
{
printf(" %d\n", head -> data);
head = head -> next;
}
}
int main()
{
struct Node *head, *prev;
int i, n;
printf("How many values you want to insert ?");
scanf("%d", &n);
printf("\nNow enter values :\n");
for(i = 0; i < n; i++){
int val;
scanf("%d", &val);
if(i == 0){
head = makeNode(val);
prev = head;
}
else{
struct Node *temp = makeNode(val);
prev->next = temp;
prev = temp;
}
}
printfList(head);
return 0;
}
Hope it helps.
I'm not sure what you're looking to do, but I think you should start by reviewing the question: should a "node" be a property of an object (a struct data type) or should a "node" be an accessor to a data type...?
Both work and I've used both.
When I need to link existing objects together, than a node will contain a reference data type... but unlike your list, the data is always accessed using a pointer (not containing the actual data type, but only using a reference).
This allows one (object) to many (lists) relationships.
However, many times the data type itself will need to be "chained" (in a single list - one to one relationship), in which case the "node" is a property of the data type and can be re-used in many different types.
A list to link existing types
Here's an example code where I used a linked list to link existing objects using a void pointer.
I'm not sure this implementation adds anything to your initial concept, but it does show the "modularization" for a "one (objet) to many (lists)" approach.
/* *****************************************************************************
Simple List
***************************************************************************** */
typedef struct fio_ls_s {
struct fio_ls_s *prev;
struct fio_ls_s *next;
void *obj;
} fio_ls_s;
#define FIO_LS_INIT(name) \
{ .next = &(name), .prev = &(name) }
/** Adds an object to the list's head. */
static inline __attribute__((unused)) void fio_ls_push(fio_ls_s *pos,
void *obj) {
/* prepare item */
fio_ls_s *item = (fio_ls_s *)malloc(sizeof(*item));
if (!item)
perror("ERROR: fiobj list couldn't allocate memory"), exit(errno);
*item = (fio_ls_s){.prev = pos, .next = pos->next, .obj = obj};
/* inject item */
pos->next->prev = item;
pos->next = item;
}
/** Adds an object to the list's tail. */
static inline __attribute__((unused)) void fio_ls_unshift(fio_ls_s *pos,
void *obj) {
pos = pos->prev;
fio_ls_push(pos, obj);
}
/** Removes an object from the list's head. */
static inline __attribute__((unused)) void *fio_ls_pop(fio_ls_s *list) {
if (list->next == list)
return NULL;
fio_ls_s *item = list->next;
void *ret = item->obj;
list->next = item->next;
list->next->prev = list;
free(item);
return ret;
}
/** Removes an object from the list's tail. */
static inline __attribute__((unused)) void *fio_ls_shift(fio_ls_s *list) {
if (list->prev == list)
return NULL;
fio_ls_s *item = list->prev;
void *ret = item->obj;
list->prev = item->prev;
list->prev->next = list;
free(item);
return ret;
}
/** Removes an object from the containing node. */
static inline __attribute__((unused)) void *fio_ls_remove(fio_ls_s *node) {
void *ret = node->obj;
node->next->prev = node->prev->next;
node->prev->next = node->next->prev;
free(node);
return ret;
}
A list that is integrated in the data-type
Often I have objects that I know I will link together and that by nature will only belong to a single list ("one to one").
In these cases, placing the node struct data within the data-type allows better locality and improved performance through a single allocation for both the data and the node information.
A good enough example for such a situation can be examined is this SO answer.

Elegant implementation of circular singly-linked list in C?

Going through classic data structures and have stopped on linked lists.Just implemented a circular singly-linked list, but I'm under overwhelming impression that this list could be expressed in a more elegant manner, remove_node function in particular.
Keeping in mind efficiency and code readability, could anybody present a more concise and efficient solution for singly-linked circular list?
#include <stdio.h>
#include <stdlib.h>
struct node{
struct node* next;
int value;
};
struct list{
struct node* head;
};
struct node* init_node(int value){
struct node* pnode;
if (!(pnode = (struct node*)malloc(sizeof(struct node)))){
return NULL;
}
else{
pnode->value = value;
}
return pnode;
}
struct list* init_list(){
struct list* plist;
if (!(plist = (struct list*)malloc(sizeof(struct list)))){
return NULL;
}
plist->head = NULL;
return plist;
}
void remove_node(struct list*a plist, int value){
struct node* current, *temp;
current = plist->head;
if (!(current)) return;
if ( current->value == value ){
if (current==current->next){
plist->head = NULL;
free(current);
}
else {
temp = current;
do {
current = current->next;
} while (current->next != plist->head);
current->next = plist->head->next;
plist->head = current->next;
free(temp);
}
}
else {
do {
if (current->next->value == value){
temp = current->next;
current->next = current->next->next;
free(temp);
}
current = current->next;
} while (current != plist->head);
}
}
void print_node(struct node* pnode){
printf("%d %p %p\n", pnode->value, pnode, pnode->next);
}
void print_list(struct list* plist){
struct node * current = plist->head;
if (!(current)) return;
if (current == plist->head->next){
print_node(current);
}
else{
do {
print_node(current);
current = current->next;
} while (current != plist->head);
}
}
void add_node(struct node* pnode,struct list* plist){
struct node* current;
struct node* temp;
if (plist->head == NULL){
plist->head = pnode;
plist->head->next = pnode;
}
else {
current = plist->head;
if (current == plist->head->next){
plist->head->next = pnode;
pnode->next = plist->head;
}
else {
while(current->next!=plist->head)
current = current->next;
current->next = pnode;
pnode->next = plist->head;
}
}
}
Take a look at the circular linked list in the Linux kernel source: http://lxr.linux.no/linux+v2.6.36/include/linux/list.h
Its beauty derives from the fact that you don't have a special struct for your data to fit in the list, you only have to include the struct list_head * in the struct you want to have as a list. The macros for accessing items in the list will handle the offset calculation to get from the struct list_head pointer to your data.
A more verbose explanation of the linked list used in the kernel can be found at kernelnewbies.org/FAQ/LinkedLists (Sorry, I dont have enough karma to post two hyperlinks).
Edit: Well, the list is a double-linked list and not a single-linked one like you have, but you could adopt the concept and create your own single-linked list.
List processing (particularly of circular lists) gets way easier when you treat the list head like an element of the list (a so-called "sentinel"). A lot of special cases just disappear. You can use a dummy node for the sentinel, but if the next pointer is first in the struct, you don't need to do even that. The other big trick is to keep a pointer to the next pointer of the previous node (so you can modify it later) whenever you modify the list. Putting it all together, you get this:
struct node* get_sentinel(struct list* plist)
{
// use &plist->head itself as sentinel!
// (works because struct node starts with the next pointer)
return (struct node*) &plist->head;
}
struct list* init_list(){
struct list* plist;
if (!(plist = (struct list*)malloc(sizeof(struct list)))){
return NULL;
}
plist->head = get_sentinel(plist);
return plist;
}
void add_node_at_front(struct node* pnode,struct list* plist){
pnode->next = plist->head;
plist->head = pnode;
}
void add_node_at_back(struct node* pnode,struct list* plist){
struct node *current, *sentinel = get_sentinel(plist);
// search for last element
current = plist->head;
while (current->next != sentinel)
current = current->next;
// insert node
pnode->next = sentinel;
current->next = pnode;
}
void remove_node(struct list* plist, int value){
struct node **prevnext, *sentinel = get_sentinel(plist);
prevnext = &plist->head; // ptr to next pointer of previous node
while (*prevnext != sentinel) {
struct node *current = *prevnext;
if (current->value == value) {
*prevnext = current->next; // remove current from list
free(current); // and free it
break; // we're done!
}
prevnext = &current->next;
}
}
void print_list(struct list* plist){
struct node *current, *sentinel = get_sentinel(plist);
for (current = plist->head; current != sentinel; current = current->next)
print_node(current);
}
A few comments:
I think the remove function doesn't correctly adjust the circular list pointers when you delete the head node and the list is larger than 3 elements. Since the list is circular you have to point the last node in the list to the new head.
You might be able to shorten the remove function slightly by creating a "find_node" function. Since the list is circular, however, there will still be the edge case of deleting the head node which will be more complex than in a non-circular list.
Code "beauty" is in the eye of the beholder. As code goes yours is easy to read and understand which beats a lot of code in the wild.
I use the following to create a dynamic circular singly linked list. All it requires is the size.
Node* createCircularLList(int size)
{
Node *it; // to iterate through the LList
Node *head;
// Create the head /1st Node of the list
head = it = (Node*)malloc(sizeof(Node));
head->id = 1;
// Create the remaining Nodes (from 2 to size)
int i;
for (i = 2; i <= size; ++i) {
it->next = (Node*)malloc(sizeof(Node)); // create next Node
it = it->next; // point to it
it->id = i; // assign its value / id
if (i == 2)
head->next = it; // head Node points to the 2nd Node
}
// close the llist by having the last Node point to the head Node
it->next = head;
return head; // return pointer to start of the list
}
And i define Node ADT like so:
typedef struct Node {
int id;
struct Node *next;
} Node;

Resources