inserting a node into a linked list - c

Assume structure list and node are defined as
struct list {struct node *a;};
struct node { int value;
struct node *next;};
The following function inserts integer e into l as the first element
void insert_first(int e, struct list *l){
struct node * r = malloc(sizeof(struct node));
r->value = e;
r->next = l->a;
l->a = r;}
Example: original list "b": 1 2 3 4
after calling insert_first(3,*b)
list "b": 3 1 2 3 4
insert_first is pretty straightfoward; however, I am having a hard time trying to figure out how to write a function insert_last which inserts a number as the last element of the list.
Example: original list "b": 1 2 3 4
after calling insert_last(3,*b)
list "b": 1 2 3 4 3
Thanks for any help in advance.

One way of doing it is to iterate over the list until you find the tail. Something like this:
void insert_last(int e, struct list *l)
{
// "iter" Will iterate over the list.
struct node *iter = l->a;
struct node *new_node = malloc(sizeof(struct node));
// Advice: ALWAYS check, if malloc returned a pointer!
if(!new_node) exit(1); // Memory allocation failure.
new_node->value = e;
new_node->next = NULL;
if(iter){
// Loop until we found the tail.
// (The node with no next node)
while(iter->next) iter = iter->next;
// Assign the new tail.
iter->next = new_node;
}else{
// The list was empty, assign the new node to be the head of the list.
l->a = new_node;
}
}
EDIT: Something I saw in your code, that really tickles me: ALWAYS check, when using malloc, whether you actually got a pointer back or not (check if the pointer is NULL). If malloc failes to allocate memory, be it for a lack thereof or some other critical error, it will toss you a NULL pointer. If you do not check for that, you might end up running in to some very nasty, hard to detect bugs. Just a little reminder!

You need to save original HEAD node and traverse through list . Hope this code will help you.
struct node {
int value;
struct node *next;
};
struct list {struct node *a;};
struct node *insert_last(int e, struct list *l) {
/* Store the initial head of the list */
struct list *org_head = head;
struct node *r = malloc(sizeof(struct node));
r->value = e;
r->next = NULL /* Assign next pointer of current node to NULL */
/* If the head is initially NULL, then directly return the new created node (r) as the head of a linked list with only one node */
if(head == NULL)
{
return r;
}
/* While we do not reach the last node, move to the next node */
while(head -> next != NULL)
head = head -> next;
/* Assign the 'next' pointer of the current node to the "r" */
head->next = r;
/* return the original head that we have stored separately before */
return org_head;
}

Related

Linked list Pointer

I am learning C and I've come up with a conceptual question about pointers.
Here is a simple code to push (add to the beginning) an int to a linked list in C.
The following code works:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int val;
struct node *next;
} node_t;
void push(node_t **head, int val) {
// head is a pointer to the pointer of the first node_t
node_t *new_node; // new pointer to a node
new_node = (node_t *)malloc(sizeof(node_t));
new_node->val = val;
new_node->next = *head;
*head = new_node;
}
int main() {
// creating the first node
node_t *head;
head = (node_t *)malloc(sizeof(node_t));
head->val = 2;
head->next = NULL;
// pushing a value
push(&head, 1); // the '&' is important
return 0;
}
As you notice, we have to pass &head as a parameter. So I though changing the function so I could pass head instead. Here's the modified function :
void push(node_t *head, int val) {
node_t **p_head;
p_head = &head; // p_head is a pointer to the pointer of the first node_t
node_t *new_node; // pointer to a new node
new_node = (node_t *)malloc(sizeof(node_t));
new_node->val = val;
new_node->next = *p_head;
*p_head = new_node;
}
Why does this version won't work ?
Thanks in advance.
You should be able to pass along the structure's pointer for the creation of another structure in a linked list. I would suggest looking at the linked list structure in a slightly different way.
Usually, in the creation of a linked list, whenever a new list item (aka structure in your case) is created, the "next node structure" pointer is set to null and the previous linked list member has its "next node structure" pointer updated to the pointer of the newly created structure. Making some revisions to your program I store some additional information in your structure and produce a linked list of ten members. Following is the revised code.
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int val;
struct node *previous; /* Added this to use with the passed node pointer */
struct node *next;
} node_t;
node_t * push(node_t *nd, int val) /* Return the pointer of the newly created node */
{
node_t *new_node; // New pointer to a node
new_node = (node_t *)malloc(sizeof(node_t));
new_node->val = val;
new_node->previous = nd;
new_node->next = NULL;
return new_node;
}
int main()
{
node_t *work; // Pointer work variable for building a linked list of nodes
node_t *head;
head = (node_t *)malloc(sizeof(node_t));
head->val = 2; /* This value will get adjusted to provide unique values */
head->previous = NULL;
// Create a set of ten nodes.
work = head;
for (int i = 0; i < 10; i++)
{
work->next = push(work, (2 * i + i + 12));
work = work->next; /* Links this node to the newly created node. */
}
// Now travel down the chain and print out the pertinent statistics of the nodes.
work = head;
while (1)
{
printf("This node's values are: this->%p value->%d previous->%p next->%p.\n", work, work->val, work->previous, work->next);
if (work->next == NULL) /* We have reached the end of the list */
break;
work = work->next;
}
return 0;
}
When I ran this program, I received the following output on my terminal.
This node's values are: this->0x55bfd6edc2a0 value->2 previous->(nil) next->0x55bfd6edc2c0.
This node's values are: this->0x55bfd6edc2c0 value->12 previous->0x55bfd6edc2a0 next->0x55bfd6edc2e0.
This node's values are: this->0x55bfd6edc2e0 value->15 previous->0x55bfd6edc2c0 next->0x55bfd6edc300.
This node's values are: this->0x55bfd6edc300 value->18 previous->0x55bfd6edc2e0 next->0x55bfd6edc320.
This node's values are: this->0x55bfd6edc320 value->21 previous->0x55bfd6edc300 next->0x55bfd6edc340.
This node's values are: this->0x55bfd6edc340 value->24 previous->0x55bfd6edc320 next->0x55bfd6edc360.
This node's values are: this->0x55bfd6edc360 value->27 previous->0x55bfd6edc340 next->0x55bfd6edc380.
This node's values are: this->0x55bfd6edc380 value->30 previous->0x55bfd6edc360 next->0x55bfd6edc3a0.
This node's values are: this->0x55bfd6edc3a0 value->33 previous->0x55bfd6edc380 next->0x55bfd6edc3c0.
This node's values are: this->0x55bfd6edc3c0 value->36 previous->0x55bfd6edc3a0 next->0x55bfd6edc3e0.
This node's values are: this->0x55bfd6edc3e0 value->39 previous->0x55bfd6edc3c0 next->(nil).
Hopefully, this might give you some food for thought on pointer usage as it pertains to linked lists. Also, since the program is using "malloc" it usually is a good idea to have some cleanup in the program to make sure the memory is freed up (e.g. use the "free()" function).
Hope that helps.
Regards.

Segmentation fault with unknown reason (C)

I was trying to solve my data structure homework, and I used doubly linked list in my code. But when I used it to create a new node and return to main, I got a segmentation fault.
my function(append) is like:
void append(struct Node** RailHead[], int new_data, int r){
/* 1. allocate node */
printf("1.\n");
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
struct Node* last = RailHead[r]; /* used in step 5*/
/* 2. put in the data */
new_node->data = new_data;
/* 3. This new node is going to be the last node, so
make next of it as NULL*/
new_node->next = NULL;
/* 4. If the Linked List is empty, then make the new
node as head */
if (RailHead[r] == NULL){
new_node-> prev = NULL;
RailHead[r] = new_node;
return;
}
/* 5. Else traverse till the last node */
while (last->next != NULL)
last = last->next;
/* 6. Change the next of last node */
last->next = new_node;
/* 7. Make last node as previous of new node */
new_node-> prev = last;
return;
}
RailHead is the pointer array that I adopted to store the different head reference of doubly linked lists, and r is the assigned rail (by input) to decide which rail should append new data.
I would like to understand what's going on with my code. If anyone can help, I will be really appreciate about it! Thank you!

Adding item in linked list C

When i want to add item to linked list my program crashes.
This are my structs that i'm using
typedef struct seats
{
int number, reserved;
char name[1000];
} seats;
// node list
typedef struct node
{
seats seat;
struct node * next;
} node_t;
And this is my insert function
void AddSeat(node_t * head, seats a_seat) // unos podataka na kraj liste
{
node_t * current = head;
while (current->next != NULL) {
current = current->next;
}
/* now we can add a new variable */
current->next = malloc(sizeof(node_t));
current->next->seat = a_seat;
current->next->next = NULL;
}
Actually I think your logic is wrong.
In a linked list you start with an empty node:
[ ]->
When you have something to store you fill the node.
[X]->
Then you create a new empty node at the end of it.
[X]->[ ]
And so forth.. And so on..
[X]->[X]->
[X]->[X]->[ ]
In your code, you are adding the value to the new element. When you are at the end of the list you assign the seat to the current node and then create a new (empty) node at the end. You should also create a variable for the node, allocate memory for it and then point the node to it.
For the linked list to work, where you have
/* now we can add a new variable */
current->next = malloc(sizeof(node_t));
current->next->seat = a_seat;
current->next->next = NULL;
you should have
void AddSeat(node_t *head, seats a_seat){
node_t *current = head;
node_t *new_node;
...
new_node = malloc(sizeof(node_t));
current->seat = a_seat;
current->next = new_node;
...
}
Also please consider following some good practices when writing code in C like ataching the pointer operator (*) to the variable name (char *var instead of char * var) and properly indent your code. It improves readability a lot.

nodes, pass by value, weird string behaviour in C

So I have a self-made double-linked-list implementation that is being used as a stand in for a queuer. (implemented in C, a language that I am admittedly weak in).
my typedef for the node:
typedef struct Node
{
char *name;
int data;
int recurring;
struct Node *next;
struct Node *prev;
}node;
which says "a node has a name, a datapoint, whether it's recurring or not and pointers to the previous and next nodes"
the insertion function like so
node * insertFromTail(node *tail, int data, int recurring, char *name)
{
node *newNode;
node *oldNext;
node *origTail = tail;
/*assume *pointer points to tail of list*/
/*printf("tail data is %d\n", tail->data);
printf("before loop\n");*/
while(tail->prev != NULL && tail->data > data)
{
/*printf("inside while loop\n");*/
tail = tail -> prev;
}
/*printf("after loop\n");*/
/*if we are looking at a no item list or tail*/
if(tail->next == NULL)
{
/*printf("pointer is tail\n");*/
return insert(tail, data, recurring, name);
}
else /*tail pointer points at item before the point of insertion*/
{
/*printf("default case\n");
printf("pointer data is %d\n", tail->data);*/
oldNext = tail->next;
newNode = (node *)malloc(sizeof(node));
newNode->data = data;
newNode->recurring = recurring;
newNode->name = name;
oldNext -> prev = newNode;
newNode -> next = oldNext;
tail -> next = newNode;
newNode -> prev = tail;
return origTail;
}
}
with the internal insert
node * insert(node *tail, int data, int recurring, char *name)
{
/* Allocate memory for the new node and put data in it.*/
tail->next = (node *)malloc(sizeof(node));
(tail->next)->prev = tail;
tail = tail->next;
tail->data = data;
tail->recurring = recurring;
tail->name = name;
tail->next = NULL;
return tail;
}
which is passed the tail of the list, the data point, the time at which the next item will recur at and the name of the item.
if we start with a node that is empty and has NULL prev and next references (a dummy node), and I add three unique nodes with a function called ADD that calls insertFromTail taking input from stdIn
int main()
{
node *start,*temp,*tail;
start = (node *)malloc(sizeof(node));
temp = start = tail;
temp->next = NULL;
temp->prev = NULL;
if(strcmp(command, "ADD") == 0)
{
scanf("%d",&argTime);
scanf("%s",&argName);
tail = insertFromTail(head, argTime, 0, *argName);
}
}
with input as so:
INPUT:
ADD 10 Gin
ADD 20 Vodka
ADD 30 Rum
PRINT
I would get an output of
OUTPUT:
Rum 10
Rum 20
Rum 30
This is an error, as the desired output would be
OUTPUT:
Gin 10
Vodka 20
Rum 30
I have a feeling it has to do with how the string is passed into the node, but as you can see, I'm stumped. This is the last thing left on the assignment and everything else is working perfectly, so I decided to ask here to see if anyone can nudge me on the right path. Thanks for your help in advance :)
P.S. Sorry for bad everything, I'm sleep deprived :(
Short answer: you'll need to duplicate that name:
tail->name = strdup(name);
Longer answer: at each iteration you're storing the same pointer. You're storing it and then the next time you're writing to it again. So you end up with 3 identical pointers to whatever you input last.
A simple fix is to duplicate the string and store a copy: precisely what strdup does. But if your implementation lacks strdup, you can try:
tail->name = malloc(strlen(name) + 1);
strcpy(tail->name, name);
Don't forget to check for errors
Don't forget to free the memory at some point

How to delete node from linked list after I print the contents?

I have a program in c which receives messages from different clients and servers. When the messages come in it adds the message to that list. After the message is added to the list I print it on the screen and on the other servers. But i want to delete the node that contains the message after it is printed so when the the print function gets called only prints the new messages. How can I delete the node after print?
Here is my struct:
typedef struct trade_list {
char* trader_msg;
u_int32_t id_of_sender;
int sender_timer;
int local_time;
struct trade_list *next;
}trade_list;
trade_list *head = NULL;
And here is how I print:
void print_trades()
{
trade_list * newnode = head;
trade_list *previous = NULL;
while (newnode) {
previous = newnode;
if ((elapsed - newnode->local_time >= 8))
printf ("%s\n", newnode->trader_msg);
newnode = newnode->next;
if (previous == NULL)
head = newnode->next;
else
{
previous->next = newnode->next;
free(newnode);
}
}
}
Thus gives me a segmentation fault. I tried changing the newnode->next to just newnode in the else part. previous->next = new node; It didn't give me an error but it did not erase the node as it kept printing that node every time the print function was called
At the start of your function:
trade_list *prev = NULL;
At each iteration in your loop, before newnode = newnode->next; add prev = newnode.
Then to delete:
if (prev == NULL) /* replace the head */
head = newnode->next;
else
prev->next = newnode->next;
/* free newnode? */
Fairly simple.
EDIT: You should really have some functions like list_create, list_add, list_remove associated with your data structure, rather than just chucking like the remove code into a print function. That's the first thing I do when I create any sort of data structure.
Another option is to have your linked list like:
typedef struct trade_node {
char* trader_msg;
u_int32_t id_of_sender;
int sender_timer;
int local_time;
struct trade_node *next;
} trade_node;
typedef struct trade_list {
trade_node *head;
/* trade_node *foot; ? */
size_t length;
} trade_list;
EDIT2: As for your edit, change print_trades to something like:
void print_trades()
{
trade_list *prev = NULL, *next;
trade_list *newnode = head;
while (newnode) {
if ((elapsed - newnode->local_time >= 8)) {
printf ("%s\n", newnode->trader_msg);
/* temp variable for newnode->next */
next = newnode->next;
if (prev == NULL) /* replace the head */
head = next;
else
prev->next = next;
/* free newnode->trader_msg? */
free(newnode);
/* don't update prev */
newnode = next;
}
else {
prev = newnode;
newnode = newnode->next;
}
}
}
In your code, previous will never be NULL since you set it to newnode at the start of the loop, and newnode also shouldn't equal newnode->next until after newnode has been processed completely. You're also using newnode after you've freed it.
Instead of having print_trades depend on the global variable head, make it receive this 'head' as an argument and print from there. It's much better design wise.
void print_trades(trade_list* head){ ... }
Then if you are adding the new nodes to the end of the list, you can print it starting from the first new one. If you are not using this information other than to print them, then there is no need to store them in a global list. Just use a local list within the function that receives them, and print that list.
Deleting a list is usually done by calling free(ptr) on each of the pointers. Since you know how to add nodes to the list, you will know how to inverse that appropiately.
Take some time to review Linked List handling and deletion of items from linked lists... once your "print" executes just do a delete...
Basically you want to have some trade_list Pointer objects that point to the node to-be deleted and the previous node. Have the previous node's "next" point to the node-to-be-deleted's next and then free the memory on the deleted node...
Start...
NODE1->NODE2->NODE3
^ ^
| |
*temp1 *temp2
temp1 = NODE1;
temp2 = NODE2; //or temp2 = temp1->next;
Next...
+-------------+
| V
NODE1 NODE2->NODE3
^ ^
| |
*temp1 *temp2
temp1->next = temp2->next;
free(temp2);
After...
NODE1-------->NODE3
//temp1 still = NODE1
//temp2 = null
Have the pointer objects iterate through the list with your while loop as you go so you don't end up out of sync. Also be sure to check for null

Resources