Doubly Linked List insertion before given element - c

I am trying to learn how to correctly work with pointers in C. Currently, I am trying to create function that would insert new node before the one, which value is given. My function looks like this:
struct list *listAddBefore(struct list *element, int insertWhat, int insertBefore)
{
element = listToFirst(element);
while (element -> next)
{
if (element -> value == insertBefore)
{
struct list *temp = listCreateElement(insertWhat, element->prev, element);
element -> prev -> next = temp;
element -> prev = temp;
return temp;
}
element = element -> next;
}
return NULL;
}
struct list *listToFirst(struct list *element)
{
while (element -> prev)
element = element -> prev;
return element;
}
struct list *listCreateElement(int value, struct list *prev, struct list *next)
{
struct list *element = (struct list *) malloc(sizeof(struct list));
element -> value = value;
element -> prev = prev;
element -> next = next;
return element;
}
What is the problem? Compiler gives me segmentation error.

Your code has one important problem
while (element->next)
should be
while (element)
since for the first element element->next = NULL and hence your function will return NULL immediately. Then you will pass again the head element and repeat that behavior on every call to this function.
Here
element->prev->next = temp;
you will dereference element->prev which must be NULL for the first node, you must check if it is valid or not, otherwise you will cause a segmentation fault. This is the correct way to link the nodes though.
I fixed your code to help you learn how to work with linked lists
struct list *listToFirst(struct list *element)
{
if (element == NULL) /* check before dereferencing */
return NULL;
while (element->previous != NULL)
element = element->previous;
return element;
}
struct list *listCreateElement(int value, struct list *prev, struct list *next)
{
struct list *element = (struct list *)malloc(sizeof(struct list));
if (element == NULL) /* check the return value of malloc before dereference */
return NULL;
element->value = value;
element->previous = prev;
element->next = next;
/*
* here we test if there is a previous node, if there is one
* we relink the node to point to element as it's next node.
*/
if (prev != NULL)
prev->next = element;
return element;
}
struct list *listAddBefore(struct list *element, int insertWhat, int insertBefore)
{
element = listToFirst(element);
while (element != NULL) /* here is the most important fix */
{
if (element->value == insertBefore)
return listCreateElement(insertWhat, element->previous, element);
/*
* Since the listCreateElement function takes care of linking the nodes
* this is all we have to do here.
*
* note: Doing the linking in the listCreateElement, makes it more clear.
*/
element = element->next;
}
return NULL;
}
/* you should also add a free function, since you allocated the structs using malloc */
void freeList(struct list *list)
{
struct list *current;
current = list;
while (current != NULL)
{
struct list *next;
next = current->next;
free(current);
current = next;
}
}
int main(int argc, char **argv)
{
struct list *element;
element = listCreateElement(0, NULL, NULL);
element = listAddBefore(element, 1, 0);
element = listAddBefore(element, 2, 1);
element = listAddBefore(element, 3, 2);
/* do something with the list */
/* free the allocated memory */
freeList(element);
return 0;
}

Related

Delete struct node using pointer-to-pointer

Suppose that I have a linked list, the next function deletes struct node from the linked list
struct list **lpp;
for (lpp = &list; *lpp != NULL; lpp = &(*lpp)->next)
{
if ((*lpp)->item == i)
{
*lpp = (*lpp)->next;
break;
}
}
please need explain about:
lpp = &(*lpp)->next, can I write it as lpp = lpp->next, is this not the same?
*lpp = (*lpp)->next
the bottom line , I do not see how this function deletes a struct node from the list
lpp points either to the first element of the list or to the next pointer of some element.
By *lpp = (*lpp)->next you are writing it directly into the memory. E.g. consider a list
| el0 | -> | el1 | -> | el2 | -> NULL
list list->next
list from you code points to el0 and lpp = &list.
Now, there are two cases:
el0 matches i: --> list becomes |el0|.next which is el1. After running this function, you have
| el1 | -> | el2 | -> NULL
list list->next
elX matches i (with X>0): lpp is &el_{X-1}.next and by *lpp = ..., this .next will point to elX.next. E.g. assuming el1 matches, you get
| el0 | -> | el2 | -> NULL
lpp = &(*lpp)->next is used to get a reference to next. A simple lpp = lpp->next does not suffice, because it are different types. When you work on lpp->next, a *lpp is like *lpp->next which would dereference the content of the next element.
Single list operations
Although unrelated to this question but due to other discussions, some more code...
Assuming a data structue like
struct node {
int data;
struct node *next;
};
In real code, data would not be a member of this node but struct node would be a mix-in within another object and something like container_of is used to access it. But for this question, keep it as above...
We can define some functions like
void slist_add(struct node *node, struct node *root)
{
node->next = root->next;
root->next = node;
}
void slist_remove(struct node **node)
{
if (node)
*node = (*node)->next;
}
struct node **slist_search(struct node *root, int key)
{
struct node **ptr;
for (ptr = &root->next; *ptr; ptr = &(*ptr)->next) {
if ((*ptr)->data == key)
return ptr;
}
return NULL;
}
Then, we use an empty struct node as an anchor:
int main(void)
{
struct node head = { .next = NULL };
/* add a node */
{
struct node *n = malloc(sizeof *n);
n->data = 23;
slist_add(n, &head);
}
/* add a node */
{
struct node *n = malloc(sizeof *n);
n->data = 42;
slist_add(n, &head);
}
/* verify our expectations... */
assert(head.next != NULL);
assert(head.next->data == 42);
assert(head.next->next != NULL);
assert(head.next->next->data == 23);
assert(head.next->next->next == NULL);
/* remove the node */
{
struct node **ptr = slist_search(&head, 42);
assert(ptr != NULL);
assert(*ptr != NULL);
assert((*ptr)->data == 42);
if (ptr) {
struct node *n = *ptr;
slist_remove(ptr);
free(n);
}
}
/* remove the node */
{
struct node **ptr = slist_search(&head, 23);
assert(ptr != NULL);
assert(*ptr != NULL);
assert((*ptr)->data == 23);
if (ptr) {
struct node *n = *ptr;
slist_remove(ptr);
free(n);
}
}
assert(head.next == NULL);
}
Your code is an extremely simplified and incomplete node delete attempt.
You have to take care of the edge cases as well as actually free the memory.
This line:
*lpp = (*lpp)->next;
is responsible for taking out the node from the list.
It only works if *lpp is the list head and there is another element on the list.
The *lpp points to the node which you do not need anymore and it is replaced by the the next node on the list
(*lpp)->next;
lpp = &(*lpp)->next, can I write it as lpp = lpp->next, is this not
the same?
No it is not. And lpp = lpp->next will not compile.
& is a dereference operator. It is obtaining the address of the node pointer.
You can write this line as
lpp = & ( (*lpp)->next );
and you can recognize (*lpp)->next as the next node pointer on the list.
lpp is a pointer to pointer. *lpp->next is expression known to the compiler but not the lpp->next.
I guess that you misunderstood
lpp = & ( (*lpp)->next );
as
lpp = &* (lpp->next);
and thought that &* would cancel itself out.
If you want to delete the node in the middle of the list you have to connect
the node which exists before the node to be deleted to the node located after the node marked for deletion.
Something similar to:
prev = current;
to_free = current->next; // node to be freed
prev->next = to_free->next; // connect nodes before deletion
free(to_free)
can you please show to me how do I delete a linked list node using
double poniters? – Fela93
I have added the test program for node deletion:
#include <stdio.h>
#include <stdlib.h>
// Basic simple single list implementation to illustrate
// a proper deletion of the node which has a specfic data value.
// Node in List
typedef struct node {
int data;
struct node* next; // pointer to next node
}node;
// returns newly created node
node* node_new(int data)
{
node* new_node = malloc(sizeof(node)); // allocate memory for the node
if (new_node == NULL)
return NULL; // protection
new_node->data = data; // remember the data
new_node->next = NULL; // no next node
return new_node; // return new created node
}
// The method creates a node and prepends it at the beginning of the list.
//
// Frequently used names for this method:
//
// insert at head
// add first
// prepend
//
// returns new head or NULL on failer
node* add_node(node **head, node* new_node)
{
// Add item to the front of the in_list, return pointer to the prepended node (head)
if(head == NULL)
return NULL;
if(new_node == NULL) // problem, not enough memory
return NULL; // in_list->head has not changed
/*
new_node
|*| --> NULL
next
*/
if(*head == NULL) // if list is empty
{
*head = new_node; // the new_node becomes a head
}
else // list already have a head node
{
/*
|2|-->|1|-->NULL
^
|
*
head (2) (list pointer)
*/
new_node->next = *head; // now, the new node next pointer points to the node pointed by the list head, see below:
/*
new_node
|3|--> |2|-->|1|-->NULL
^
|
*
head (list pointer)
*/
*head = new_node; // the list head has to move to new_node ( a new prepanded node)
/*
new_node
|3|--> |2|-->|1|-->NULL
^
|
*
head (3) (list pointer)
*/
}
return *head; // we are returning pinter to new_node
}
// Print out list
void print_nodes(node** head)
{
node* node;
if (head == NULL) {
return;
}
if (*head == NULL){
printf("List is empty!\n");
return;
}
printf("List: ");
node = *head;
while(node != NULL)
{
printf(" %d", node->data);
node = node->next;
}
printf("\n");
}
struct node *find(struct node *start, int data) // find p to be removed
{
node* node;
if (start == NULL)
return NULL;
node = start;
while(node != NULL)
{
if (node->data == data)
return node;
node = node->next;
}
return NULL;
}
int delete(struct node **start, int data)
{
struct node *p, *prev, *next, *to_free;
if (start == NULL) // protection
return 0;
p = find(*start, data); // find element to be removed
if (p == NULL)
return 0;
if (*start == NULL)
return 0; // protection
if(*start == p) // head == p
{
if((*start)->next !=NULL)
{
*start = (*start)->next; // move head
printf("Will be removed: %p\n",p);
free(p); // remove old head
return 1;
}
else // the only node
{
free(p); // free the node pointed by *start (header)
printf("Last node removed\n");
*start = NULL; // header points to NULL
return 1;
}
}
// p != start:
next = *start;
while (next != NULL)
{
prev = next;
to_free = next->next; // candidate to be freed
if( to_free == p )
{
prev->next = to_free->next; // connect nodes before deletion
free(to_free); // now free the remembered `next`
to_free = NULL; // so it does not point to the released memory
return 1;
}
next = next->next; // this node was not a match
} //while
return 0;
}
int main() {
node *head = NULL;
printf("head: %p\n", head);
node *n1 = node_new(1);
node *n2 = node_new(2);
node *n3 = node_new(3);
print_nodes(&head);
add_node(&head, n1);
add_node(&head, n2);
add_node(&head, n3);
printf("head points to: %p\n", head);
// list has 3 elements
print_nodes(&head);
delete(&head, 3);
print_nodes(&head);
delete(&head, 1);
print_nodes(&head);
delete(&head, 2);
print_nodes(&head);
printf("head points to: %p\n", head);
print_nodes(&head);
return 0;
}
Output:
head: (nil)
List is empty!
head points to: 0x5617cd3802b0
List: 3 2 1
Will be removed: 0x5617cd3802b0
List: 2 1
List: 2
Last node removed
List is empty!
head points to: (nil)
List is empty!

Delete duplicates from linked list and save it to another list in C

I encountered a problem during this task. I'm just take list, check that currently processed element is in it. If is skip it, else add to new list.
I wrote three function to do this. One that search particular element, next which is checking for element exist in new list, and the last which is get everything together.
I've tried to do this in two ways:
First checking for occurrence in "old" list, it works, but not at all ( writes to new list in descending order) also I think for particular example it won't work.
Second checking for occurrence of element in currently created list, but this doesn't work.
Here is the code:
struct list *search_node(struct list *prt, char *to_search) {
is_empty();
short is_found = -1;
while (prt != NULL && ((is_found = strcmp(prt->word, to_search) != 0))) {
prt = prt->next;
}
if (!is_found)
return prt;
else
return NULL;
}
bool is_on_list(struct list *ptr, char *str) {
if (search_node(ptr, str) != NULL)
return 1;
else
return 0;
}
struct list *without_repetiton(struct list *head) {
struct list *new_list = NULL;
struct list **new_el = &new_list;
struct list *prt1 = head, *check;
while (prt1 != NULL) {
//printf("test = %s\n", prt1 -> word);
check = new_list;
if (!is_on_list(prt1->next, prt1->word)) { // or (new_list, prt1 -> word)
*new_el = (struct list *)malloc(sizeof(struct list));
memcpy(*new_el, prt1, sizeof(struct list));
new_el = &((*new_el)->next);
}
prt1 = prt1->next;
}
return new_list;
}
There is the structure of list:
struct list {
char *word;
struct list *next;
struct list *prev;
};
I have two questions, first why the first approach writes the list in descending order, and second why when I've tried to search occurrence of word in already created list in not work?
IO samples:
When : is_on_list(prt1->next, prt1->word))
Fist list: One, One, Two
Second list: Two, One
When : is_on_list(new_list, prt1->word))
The first list is the same as second.
Your code does not construct the duplicate list correctly: simplify the code and link the new elements by hand instead of using memcpy():
struct list *search_node(struct list *ptr, const char *to_search) {
while (ptr != NULL) {
if (!strcmp(ptr->word, to_search))
return ptr;
}
return NULL;
}
bool is_on_list(struct list *ptr, const char *str) {
return search_node(ptr, str) != NULL;
}
struct list *without_repetiton(struct list *head) {
struct list *new_list = NULL;
struct list *tail = NULL;
for (struct list *ptr = head; ptr != NULL; ptr = ptr->next) {
if (!is_on_list(new_list, ptr->word)) {
struct list *node = malloc(sizeof(*node));
node->next = NULL;
node->prev = tail;
node->str = strdup(ptr->word);
if (tail == NULL) {
new_list = tail = node;
} else {
tail->next = node;
tail = node;
}
}
}
return new_list;
}

Trying to access elements of linked-list structures in C and calling functions on struct elements

I am starting out on C and i was just wondering how I would declare these linked lists structures in the main function so that I could call the functions on them, and then how I would print the values from the elements of the linked list.
Thanks for the help
#include <stdio.h>
#include <stdlib.h>
void main() {
}
struct element {
struct element * next;
int data;
};
struct linked_list {
struct element * head;
};
void append_int(struct linked_list * list, int val) {
struct element * elem = malloc(sizeof(struct element));
elem->data = val;
elem->next = NULL; // Really important to explicitly set this to null. Malloc does not zero memory
if (list->head == NULL) {
// Empty list, we need to append to head
list->head = elem;
} else {
// List has some elements, find the end and append to that
struct element * tail = list->head;
while (tail->next != NULL) {
tail = tail->next;
}
tail->next = elem;
}
}
void deletehead(struct linked_list * list) {
while(list->head) {
struct element * temp_head = list->head->next;
free(list->head);
list->head = temp_head;
}
}
void inserthead(struct linked_list * list, int val) {
struct element * new_node = malloc(sizeof(struct element));
new_node->data = val;
struct element * temp_head2 = list->head;
list->head = new_node;
new_node->next = temp_head2;
}
you can create the struct linked_list, that will hold the pointer to the first "link", the first element that is your "object" like in Object Oriented programming.
also don't forget to forward declare your functions if needed!
to create a linked list:
struct linked_list* list = malloc(sizeof(linked_list));
to call functions on it:
inserthead(list, 5);
if you are coming from an oop background, all functions are static, you can think of passing the pointer to the function as calling it like "list.insert()".

C programming, double link list copy-over issue

I'm having some trouble copying a single linklist over to a double-linklist. Not sure what is going on but I'm having a gdb debugging error:
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x0000000000000000
0x0000000100000d86 in doublify (list=0x1001008c0) at lists.c:62
62 newDlist->item = curr->item;
The one-directional link list is working,
My .h Header File:
typedef struct _node {
Item item;
link next;
} node;
typedef struct _dnode *dlink;
typedef struct _dnode {
Item item;
dlink prev;
dlink next;
} dnode;
My Code:
link newLink (Item item){
link createLink = malloc(sizeof(node));
createLink->item = item;
return createLink;
}
link fromTo (int start, int end) {
link newList = NULL;
if(start <= end ){
newList = newLink(start);
newList->next = fromTo(start+1, end);
}
return newList;
}
//Heres where it isn't able to copy the linklist item over into the new dlist.
dlink doublify (link list) {
dlink newDlist = malloc (sizeof (dnode));
link curr = list;
while(curr != NULL){
newDlist->item = curr->item;
curr = curr->next;
newDlist = newDlist->next;
}
return newDlist;
}
In your doublify function, you only allocate enough space for the first dnode in your doubly-linked list. As you walk along the singly-linked list using curr, you'll need to allocate space for a new dnode at each loop iteration, one for each element in the singly-linked list.
You receive the error because on the second iteration you're trying to access newDlist->next, which is an uninitialized memory address.
Note that while creating the doubly-linked list you'll also need to keep a tmp pointer to the previous dnode in order to set the prev/next pointers correctly.
The problem happens on the second iteration of the while loop. When you assign newDlist to the 'next' item, the 'next' field might contain any value. The thing is that malloc simply gives you a pointer to a data region where any values might be (it doesn't clean it or init in some way).
You simply need to allocate a new node on each iteration and setup the pointers appropriately. Here is one of the ways how that can be done.
dlink prevNode = NULL;
// Insert the first item (if present) to simplify the loop
if ( curr != NULL )
{
dlink newDlist = malloc(sizeof(dnode));
newDlist->item = curr->item;
newDlist->next = NULL;
newDlist->prev = NULL;
prevNode = newDlist;
curr = curr->next;
}
while ( curr != NULL )
{
dlink newDlist = malloc(sizeof(dnode));
newDlist->item = curr->item;
prevNode->next = newDlist;
newDlist->prev = prevNode;
newDlist->next = NULL;
prevNode = newDlist;
curr = curr->next;
}
Maksim has a good answer that helped me, but to simplify the answer if you have...
void DisplayList(topNode* nodeType) {
node* ptrNode = nodeType;
while (ptrNode->next != NULL) {
// DO WORK
}
}
...then you need to change it to...
void DisplayList(topNode* nodeType) {
node* ptrNode = new node; // THIS IS THE KEY...ALLOCATE THE MEMORY
if (ptrNode == NULL)
cout << "Could not allocate memory -- exiting application!" << endl;
else {
ptrNode = nodeType; // THEN COPY THE TOP NODE POINTER
while (ptrNode->next != NULL) {
// DO WORK
}
}
}
I ran into this same problem in my class, so maybe this will save someone some effort in the future!

Double linked list prepend element by ref in C

I try to write double linked list in C.
This is my implementation:
typedef struct
{
void* value;
struct Dlist* prev;
struct Dlist* next;
} Dlist;
Dlist* createDlist()
{
Dlist* newList = (Dlist*)malloc (sizeof(Dlist));
newList->value = NULL;
newList->next = NULL;
newList->prev = NULL;
return newList;
}
/*
* Get last element from Dlist
*/
Dlist* getLast(Dlist* list)
{
if (list)
{
while(list->next)
list = (Dlist*)list->next;
}
return list;
}
/*
* add element to list at start
*/
Dlist* addItemAtStart(Dlist* list, Pair* value)
{
Dlist* newList = NULL;
Dlist* last = NULL;
newList = createDlist ();
newList->value = value;
if (list)
{
last = getLast(list);
last->next = newList;
newList->prev = last;
return list;
}
else
return newList;
}
Now, when i try to add element to my list, i need assign a new value every time:
list = addItemAtStart(list, "Hello");
But i want only
addItemAtStart(list, "Hello");
Without list = How can i make so that list will change without assign?
p.s. I get segfaut with Dlist* addItemAtStart(Dlist **list, void* value)
I try to insert so:
Dlist **list = NULL;
addItemAtStart(&list, "Hello");
Thank you.
If you handle the list by pointing to its first element, maybe you should use double indirection:
void addItemAtStart(Dlist** plist, Pair* value)
{
// replace all list with *plist
}
addItemAtStart(&list, "Hello");
You can write your function to accept a pointer to a pointer to a List:
Dlist* addItemAtStart(Dlist** list, Pair* value)
Just make sure you add another level of indirection inside of addItemAtStart when using list.
The function can be called using
addItemAtStart(&list, "Hello");
Give reference of the head node to insert node at start.
Dlist* addItemAtStart(Dlist** list, Pair* value)
{
Dlist* newList = NULL;
Dlist* last = NULL;
newList = createDlist();
newList->value = value;
if (list)
{
last = getLast(*list);
last->next = newList;
newList->prev = last;
}
else
*list = newList
for achieving that, you need to create a static linked list node pointer.
make sure that the atitematstart method updates that node.
Using a global list will solve your problem. In the function, assign the value to the list object. I have tried it.
Your code with some corrections and inclusions:
#include <stdio.h>
#include <stdlib.h>
struct node{
void* value;
struct node *prev, *next;
};
/*This Function is Unnecessary
struct node * createList(){
struct node *newNode=malloc(sizeof(struct node));
if (newNode==NULL) return NULL;
newNode->value = NULL;
newNode->next = NULL;
newNode->prev = NULL;
return newNode;
}
*/
/*
*This Function is also Unnecessary
*Get last element from Dlist
struct node* getLast(struct node* node){
if (node==NULL) return NULL;
while (node->next!=NULL) node=node->next;
return node;
}
*/
/*
*Description: add element to list at start
*
*Return Values:
*0:Failed
*1:Succeeded
*/
int addItemAtStart(struct node **head, void *value){
struct node *newNode=malloc(sizeof(struct node));
/*Sometimes malloc can't allocate memory and returns NULL so you have to check it and if malloc couldn't allocate memory you have to exit the function*/
if (newNode==NULL) return 0;
newNode->value=value;
newNode->prev=NULL;
newNode->next=*head;
if (*head!=NULL) (*head)->prev=newNode;
*head=newNode;
return 1;
}
int main(){
struct node *list=NULL;
addItemAtStart(&list, "apple");
addItemAtStart(&list, "lemon");
addItemAtStart(&list, "orange");
addItemAtStart(&list, "peach");
return 0;
}

Resources