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.
Related
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.
I am working on a problem in which I have a method that is supposed to insert a node into a doubly linked list in a sorted manner. Here is my node and list structure:
typedef struct NodeStruct Node;
//struct for each office item
struct NodeStruct {
int id;
struct NodeStruct *next;
struct NodeStruct *prev; //Create doubly linked list node
};
/** Structure for the whole list, including head and tail pointers. */
typedef struct {
/** Pointer to the first node on the list (or NULL ). */
Node *head;
Node *last;
} List;
When I attempt to print the list of items, the item what I am trying to insert does not appear. For instance, if I try to insert 15 into this list
1 -> 2 -> 3 -> 5 -> 7,
15 does not appear at the end. Here is my insert method:
void insert(int idInsert, List *list)
{
//Initialize data for node
int idInsert;
//Insert the record based on the ID if no duplicates exist
//Special case: insert at front if idInsert is less than the ID of the current head
if (idInsert < list->head->id) {
//Make the node with idInsert the first node
Node *new = (Node *)malloc(sizeof(Node)); //Allocate memory for the new node
//Add in data
new->id = idInsert;
new->next = list->head;
list->head = new;
} else { //Locate the node before the point of insertion
//Allocate memory for the node
Node *new = (Node *)malloc(sizeof(Node));
//Add in data
new->id = idInsert;
Node *current = list->head;
while (current->next != NULL && current->next->id < new->id) {
current = current->next;
}
new->next = current->next;
if (current->next != NULL) {
new->next->prev = new;
}
current->prev->next = new;
new->prev = current;
}
//Print this message if successful
printf("RECORD INSERTED: %d\n", idInsert);
}
I am also going to include some minimal reproducible code below:
#include <stdlib.h>
#include <stdio.h>
typedef struct NodeStruct Node;
//struct for each office item
struct NodeStruct {
int id;
struct NodeStruct *next;
struct NodeStruct *prev; //Create doubly linked list node
};
/** Structure for the whole list, including head and tail pointers. */
typedef struct {
/** Pointer to the first node on the list (or NULL ). */
Node *head;
Node *last;
} List;
List *list;
List *makeList();
void insert(int idInsert, List *list);
static void *addRecord(List *list, int newID);
static void printReverse(List *list);
int main(int argc, char **argv) {
//Create an empty list for you to start.
list = (List *)makeList();
addRecord(list, 1);
addRecord(list, 2);
addRecord(list, 3);
addRecord(list, 4);
addRecord(list, 7);
insert(15, list);
printReverse(list);
}
List *makeList()
{
List *list = (List *) malloc( sizeof( List ) );
list->head = NULL;
list->last = NULL;
return list;
}
void insert(int idInsert, List *list)
{
//Insert the record based on the ID if no duplicates exist
//Special case: insert at front if idInsert is less than the ID of the current head
if (idInsert < list->head->id) {
//Make the node with idInsert the first node
Node *new = (Node *)malloc(sizeof(Node)); //Allocate memory for the new node
//Add in data
new->id = idInsert;
new->next = list->head;
list->head = new;
} else { //Locate the node before the point of insertion
//Allocate memory for the node
Node *new = (Node *)malloc(sizeof(Node));
//Add in data
new->id = idInsert;
Node *current = list->head;
while (current->next != NULL && current->next->id < new->id) {
current = current->next;
}
new->next = current->next;
if (current->next != NULL) {
new->next->prev = new;
}
current->prev->next = new;
new->prev = current;
}
//Print this message if successful
printf("RECORD INSERTED: %d\n", idInsert);
}
static void *addRecord(List *list, int newID) {
//Allocate memory for the node
Node *new = (Node *)malloc(sizeof(Node));
//Add in data
new->id = newID;
new->prev = NULL;
//New node has no next, yet
new->next = NULL;
Node **next_p = &list->head;
while (*next_p) {
next_p = &(*next_p)->next;
}
*next_p = new;
list->last = new;
new->prev = *next_p;
return EXIT_SUCCESS;
}
static void printReverse(List *list) {
Node **tail = &list->last;
printf("LIST IN REVERSE ORDER:\n");
//Traversing until tail end of linked list
while (*tail) {
printf("Item ID: %d\n", (*tail)->id);
tail = &(*tail)->prev;
}
}
It seems like my addRecord method is working fine (this functions to add values to the end of the linked list), but my insert method is not working properly. When I execute the minimal reproducible code above, I am stuck in an infinite loop. My desired result after calling printReverse would be:
Item ID: 15
Item ID: 7
Item ID: 4
Item ID: 3
Item ID: 2
Item ID: 1
Could someone please point out what is going wrong in my insertion method?
Insert has three cases:
Insert at the start.
Insert at the middle.
Insert at the end.
Your weapon to sketch out your algorithm is a piece of a paper and a pencil, where you will draw what your code is doing.
Insert at the start
Your case for inserting at the start is not complete, since you need to set the new node's previous pointer to NULL, and the previous pointer of the node that was the old head should now be pointing to the newly created node.
That could be done like this:
Node *new = malloc(sizeof(Node)); //Allocate memory for the new node
list->head->prev = new;
new->prev = NULL;
// rest of your code
Insert at the end
Anyway, to answer your question, in your example, you could simply use the addRecord() method that appends a node in the list, when the node to be inserted goes to the end, like in your example, the node with id 15.
You can do it like this:
Node *current = list->head;
while (current->next != NULL && current->next->id < new->id) {
current = current->next;
}
// if the new node is the last one
if(current->next == NULL)
{
// append it to the list
addRecord(list, idInsert);
printf("RECORD INSERTED: %d\n", idInsert);
return;
}
assuming you are using the method addRecord() discussed in your previous question, and not the one you provide here.
But as #SomeProgrammerDude commented, you could simplify that by checking if the new node is greater than the last node, and if yes, you call the addRecord().
Insert at the middle
In the case of having only node with id 1 in the list, and you insert the node with id 15 at the end, this invokes Undefined Behavior:
current->prev->next = new;
since the current node (with id 1) has no previous node, thus it's set to NULL. So you are requesting for the next field in something not a structure or a union.. Same for having 1 and 15 already in the list, and trying to insert 5.
Try changing that to:
current->next = new;
However, with your code, you will request the id of list->head, even if the list is empty, meaning that head (and last) pointer is NULL. That will invoke Undefined Behavior (UB), which is likely to result in a segmentation fault.
For that reason, in the following code I will first check if the list is empty or if the new node shall be inserted at the end, since in both cases it is enough to just call the addRecord() method (which appends a node to the list).
The condition of the if statement is going to be this:
if (list->last == NULL || idInsert > list->last->id)
which, due to short circuiting is going to be evaluated in the following order:
If the last pointer is NULL, then for sure the condition will be evaluated to true since the operator is the logical OR, so a single true operand will suffice to determine what the overall outcome of the condition is going to be. That means, that it won't evaluate the second operand, so the last pointer will not be dereferenced (which would invoke UB, since we would be requesting the id of NULL).
Putting everything together:
#include <stdlib.h>
#include <stdio.h>
typedef struct NodeStruct Node;
//struct for each office item
struct NodeStruct {
int id;
struct NodeStruct *next;
struct NodeStruct *prev; //Create doubly linked list node
};
/** Structure for the whole list, including head and tail pointers. */
typedef struct {
/** Pointer to the first node on the list (or NULL ). */
Node *head;
Node *last;
} List;
List *list;
List *makeList();
void insert(int idInsert, List *list);
static void *addRecord(List *list, int newID);
static void printReverse(List *list);
int main(void) {
//Create an empty list for you to start.
list = (List *)makeList();
addRecord(list, 1);
addRecord(list, 2);
addRecord(list, 3);
addRecord(list, 4);
addRecord(list, 7);
insert(6, list);
insert(0, list);
insert(15, list);
printReverse(list);
}
List *makeList()
{
List *list = (List *) malloc( sizeof( List ) );
list->head = NULL;
list->last = NULL;
return list;
}
//Insert the record based on the ID if no duplicates exist
void insert(int idInsert, List *list)
{
// Insert at end, if list is empty or if id is greater than all existing ids
// Short circuting protects from derefercing a NULL pointer
if (list->last == NULL || idInsert > list->last->id) {
addRecord(list, idInsert);
} else if (idInsert < list->head->id) { // Insert at start
//Make the node with idInsert the first node
Node *new = malloc(sizeof(Node)); //Allocate memory for the new node
list->head->prev = new;
new->prev = NULL;
//Add in data
new->id = idInsert;
new->next = list->head;
list->head = new;
} else { // Insert in the middle
//Locate the node before the point of insertion
//Allocate memory for the node
Node *new = malloc(sizeof(Node));
//Add in data
new->id = idInsert;
Node *current = list->head;
while (current->next != NULL && current->next->id < new->id) {
current = current->next;
}
new->next = current->next;
if (current->next != NULL) {
new->next->prev = new;
}
current->next = new;
new->prev = current;
}
//Print this message if successful
printf("RECORD INSERTED: %d\n", idInsert);
}
static void *addRecord(List *list, int newID)
{
//Allocate memory for the node
Node *new = malloc(sizeof(Node));
//Add in data
new->id = newID;
new->prev = list->last;
new->next = NULL;
list->last = new;
// if list is empty
if(!list->head)
{
list->head = new;
return EXIT_SUCCESS;
}
Node **next_p = &list->head;
while (*next_p) {
next_p = &(*next_p)->next;
}
*next_p = new;
return EXIT_SUCCESS;
}
static void printReverse(List *list) {
Node **tail = &list->last;
printf("LIST IN REVERSE ORDER:\n");
//Traversing until tail end of linked list
while (*tail) {
printf("Item ID: %d\n", (*tail)->id);
tail = &(*tail)->prev;
}
}
Output:
RECORD INSERTED: 6
RECORD INSERTED: 0
RECORD INSERTED: 15
LIST IN REVERSE ORDER:
Item ID: 15
Item ID: 7
Item ID: 6
Item ID: 4
Item ID: 3
Item ID: 2
Item ID: 1
Item ID: 0
Appendix
Notice how I approach the special cases of insert at the start and end before tackling the middle case. That is because your list has head and last pointers, these special insertions can get done in constant time, O(1), since you don't have to scan (iterate over) the list.
However, in the middle insertion, you have to scan the list, in order to locate the appropriate index, and then insert the node at that index.
Remember: the operation of traversing a list can take linear time (traversing the whole list), which in asymptotic notation is O(n), where n is the size of the list.
PS: I also checked the next pointer, by using the print (in normal order) method discussed in the linked question.
PPS: When you are done, do not forget to free the list. I have a method for this in List (C), which is the same for a double linked list, except, that you also have to set the head and last pointers to NULL too.
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;
}
typedef struct LIST{
int count = 0;
}LIST;
typedef struct NODE{
int data;
struct NODE *link;
}NODE;
int main() {
NODE *p1, *p2, *p3;
p1 = (NODE*)malloc(sizeof(NODE));
p1->link = NULL;
p2 = (NODE*)malloc(sizeof(NODE));
p2->data = 20;
p2->link = NULL;
p1->link = p2;
I want to make add NODE function and list to control NODE.
Give me some answer to solve this problem.
you should define head in the list.
node * head;
Insert function as follows, to insert value in ascending order.
void insert(int val)
{
node * nd = new node();
nd->val = val;
if(head == NULL)
head = nd;
else
{
if(val <= head->val)
{
nd->next = head;
head = nd;
}
else
{
node * itr = head;
while(itr->next != NULL && itr->next->val <= val)
itr = itr->next;
nd->next = itr->next;
itr->next = nd;
}
}
}
First you probably want to add to your LIST struct a field "NODE *first", which points to NULL initially, and then will point to the first element of your list.
Then what does you add function should do? Add to the beginning or the end of the list?
If at the beginning: allocate a NODE, set its link pointer to the first element of your list and say that the first element of the list is now the node that you just allocated.
Try to give variable according to their work, so that it is easy to understand.
struct node
{
int val;
struct node* next;
};
void insert(struct node** head_ref, int data)
{
struct node* new_node = (struct node*)malloc(sizeof(struct node));
new_node->val = data;
new_node->next = (*head_ref);
(*head_ref) = new_node;
}
int main()
{
struct node* head = NULL;
insert(&head,1);
insert(&head,2);
return 0;
}
Note that : Insert function will always add the value at front.
Try to write function for particular task.
I'll avoid giving you the entire answer in C code since it's in general better to "teach a man to fish".
I would suggest that you add a NODE * member to your LIST class to store the header node of your linked list.
The addNode that adds a node to the next node should look like this:
void addNode (LIST* list, NODE * penultNode, int newData);
// list: Address to the linked list info object
// penultNode: Address to the node after which you want to add a new node.
// Should be NULL if your linkedlist is empty
// newData: Data in the new node that you wanna add
Inside this function, your actions will depend on whether penultNode is NULL or not. If it is not null, your job is simple. You just allocate a new NODE object and set the pointer of penultNode->next to the new object. If it is NULL, that means that no node exists in the list yet. In this case, you will need to set the pointer of list->headerNode to the new NODE object.
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