Add duplicate items(string) in doubly linked list - c

I am currently figuring out the implementation of double linked list. As strange as it may sound, I want repetitive items added to my linked list.
I am adding newNode to the list in sorted order.
The below function does not add the repetitive nodes.
struct Node
{
char name[42];
struct Node *next;
struct Node *prev;
};
void addSorted(struct Node **head, struct Node *newNode)
{
struct Node* current;
// Special case for the head end
if ((*head == NULL) || strcmp((*head)->name, newNode->name) >= 0)
{
newNode->next = *head;
*head = newNode;
}
else
{
// Locate the Node before the point of insertion
current = *head;
while (current->next != NULL &&
strcmp(current->next->name, newNode->name) <= 0)
{
current = current->next;
}
newNode->next = current->next;
current->next = newNode;
}
}
struct Node* GetNewNode(char *name)
{
struct Node* newNode = malloc(sizeof (struct Node));
strcpy(newNode->name, name);
newNode->prev = NULL;
newNode->next = NULL;
return newNode;
}
int main(void)
{
// Some Irrelevant Code
if (strncmp(operator, "a", 1) == 0)
{
temp = GetNewNode(name);
addSorted(&head, temp);
}
}

I think the main point is that you have not taken care of the prev pointer and also for the first if, there should be two cases,
if(*head==NULL)
{
*head=newNode;
}
else if(strcmp((*head)->name, newNode->name) >= 0)
{
(*head)->prev=newNode;//ADD THIS LINE
newNode->next = *head;
*head = newNode;
}
In the else condition make the following changes
newNode->next = current->next;
current->next->prev = newNode;//CHANGE HERE
current->next=newNode;//ADD THIS LINE
newNode->prev=current;//ADD THIS LINE

In addition to manager the prev pointer as already discussed, there are some additional areas where you are asking for trouble. First it is wise to use a define to set the size of your static name array (this will become a necessity to validate the size of name):
#define MAXN
struct Node
{
char name[MAXN]; /* use a define for static allocation size */
struct Node *next;
struct Node *prev;
};
This feeds into two issues in GetNewNode. First you need to validate your memory allocation:
struct Node* newNode = malloc(sizeof (struct Node));
if (!newNode) { /* validate all memory allocations */
fprintf (stderr, "%s() memory allocation failed.\n", __func__);
exit (EXIT_FAILURE);
}
You then must also validate the length of name to prevent writing beyond the end of your array if name > 41 chars:
size_t namelen = strlen (name);
if ( namelen > MAXN - 1) { /* validate string length */
fprintf (stderr, "%s() name length (%zu) exceeds %d .\n",
__func__, namelen, MAXN);
return NULL;
}
Note: by using a define to set the length of name, the define MAXL is available to you as your length validation test.
Next, in GetNewNode you validate the length of name and returned NULL -- you must now handle the return in main() along with providing a declaration for head:
int main (void)
{
struct Node *head = NULL; /* head must be declared */
if (strncmp(operator, "a", 1) == 0)
{
temp = GetNewNode(name);
if (temp) /* validate return */
addSorted(&head, temp);
}
}
If your intent was to create a circular-list then you have several additional conditions you must test for and respond appropriately to in addSorted. Specifically, you must (1) create the list when *head = NULL.
If your earlier statement newNode->next = *head; *head = newNode; was correct, you must then (2) account for the condition when the list is self-referencial (i.e. only one-node present that refers to itself).
You then have two more conditions to test (3) whether newNode->name sorts before the current (*head)->name where you must insert newNode as the new first node in the list; and finally (4) the case where newNode->name sorts after the current (*head)->name.
Even with a linear head/tail list with you will need to address both (3) & (4) above. Let me know if you have further questions.

With a doubly linked list, it is best to first find the spot where you need to insert it.
// pseudo code
current = head;
while (current)
{
if ( strcmp( name, current -> name) ... ) // your logic for your sort order
{
}
current = current->next;
}
Once you find the spot to insert, you have one four cases to deal with when you want to insert an item into the into the list. You have to handle head/tail changing as well as pointing inward and outward or to null as needed.
Add to a completely empty list (head and tail point to the record, prev and next are null)
Add to the front (head gets a new value, new record prev is null,)
Add to end ( tail gets a new value, new record next is null)
Add to middle ( head/tail unchanged )

Related

Removing unique elements in a doubly linked list in C

I need a little help removing unique characters in a doubly linked list in C. So here's the logic I tried implementing: I counted the occurrence of each character in the doubly linked list. If it's occurrence is 1 time, then it is unique element and needs to be deleted. I'll be repeating the process for all elements. But my code in remove_unique_dll() function isn't working properly, please help me fix it. Here's my code-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
char data;
struct node *next;
struct node *prev;
};
struct node *head, *tail = NULL; //Represent the head and tail of the doubly linked list
int len;
void addNode(char data)
{
struct node *newNode = (struct node*) malloc(sizeof(struct node)); //Create new node
newNode->data = data;
if (head == NULL)
{ //If dll is empty
head = tail = newNode; //Both head and tail will point to newNode
head->prev = NULL; //head's previous will point to NULL
tail->next = NULL; //tail's next will point to NULL, as it is the last node of the list
}
else
{
tail->next = newNode; //newNode will be added after tail such that tail's next points to newNode
newNode->prev = tail; //newNode's previous will point to tail
tail = newNode; //newNode will become new tail
tail->next = NULL; //As it is last node, tail's next will point to NULL
}
}
void remove_unique_dll()
{
struct node *current = head;
struct node *next;
struct node *prev;
int cnt;
while (current != NULL)
{
next = current->next;
cnt = 1;
//printf("!%c ",next->data);
while (next != NULL)
{
if (next->data == current->data)
{
cnt += 1;
next = next->next;
}
else
next = next->next;
//printf("#%c %d %c\n",next->data,cnt,current->data);
}
if (cnt == 1)
{
prev = current->prev;
//printf("#%c %d",prev->data,cnt);
if (prev == NULL)
{
head = next;
}
else
{
prev->next = next;
}
if (next == NULL)
{
tail = prev;
}
else
{
next->prev = prev;
}
}
current = current->next;
//printf("#%c ",current->data);
}
head = current;
}
void display()
{
struct node *current = head; //head the global one
while (current != NULL)
{
printf("%c<->", current->data); //Prints each node by incrementing pointer.
current = current->next;
}
printf("NULL\n");
}
int main()
{
char s[100];
int i;
printf("Enter string: ");
scanf("%s", s);
len = strlen(s);
for (i = 0; i < len; i++)
{
addNode(s[i]);
}
printf("Doubly linked list: \n");
display();
remove_unique_dll();
printf("Doubly linked list after removing unique elements: \n");
display();
return 0;
}
The output is like this-
If you uncomment the printf() statements inside remove_unique_dll() you'll notice that no code below inner while loop is being executed after inner while loop ends. What's the issue here and what's the solution?
Sample input- aacb
Expected output- a<->a<->NULL
Some issues:
You shouldn't assign head = current at the end, because by then current is NULL
The next you use in the deletion part is not the successor of current, so this will make wrong links
As you progress through the list, every value is going to be regarded as unique at some point: when it is the last occurrence, you'll not find a duplicate anymore, as your logic only looks ahead, not backwards.
When you remove a node, you should free its memory.
Not a big issue, but there is no reason to really count the number of duplicates. Once you find the first duplicate, there is no reason to look for another.
You should really isolate the different steps of the algorithm in separate functions, so you can debug and test each of those features separately and also better understand your code.
Also, to check for duplicates, you might want to use the following fact: if the first occurrence of a value in a list is the same node as the last occurrence of that value, then you know it is unique. As your list is doubly linked, you can use a backwards traversal to find the last occurrence (and a forward traversal to find the first occurrence).
Here is some suggested code:
struct node* findFirstNode(char data) {
struct node *current = head;
while (current != NULL && current->data != data) {
current = current->next;
}
return current;
}
struct node* findLastNode(char data) {
struct node *current = tail;
while (current != NULL && current->data != data) {
current = current->prev;
}
return current;
}
void removeNode(struct node *current) {
if (current->prev == NULL) {
head = current->next;
} else {
current->prev->next = current->next;
}
if (current->next == NULL) {
tail = current->prev;
} else {
current->next->prev = current->prev;
}
free(current);
}
void remove_unique_dll() {
struct node *current = head;
struct node *next;
while (current != NULL)
{
next = current->next;
if (findFirstNode(current->data) == findLastNode(current->data)) {
removeNode(current);
}
current = next;
}
}
You have at least three errors.
After counting the number of occurrences of an item, you use next in several places. However, next has been used to iterate through the list. It was moved to the end and is now a null pointer. You can either reset it with next = current->next; or you can change the places that use next to current->next.
At the end of remove_unique_dll, you have head=current;. There is no reason to update head at this point. Whenever the first node was removed from the list, earlier code in remove_unique_dll updated head. So it is already updated. Delete the line head=current;.
That will leave code that deletes all but one occurrence of each item. However, based on your sample output, you want to leave multiple occurrences of items for which there are multiple occurrences. For that, you need to rethink your logic in remove_unique_dll about deciding which nodes to delete. When it sees the first a, it scans the remainder of the list and sees the second, so it does not delete the first a. When it sees the second a, it scans the remainder of the list and does not see a duplicate, so it deletes the second a. You need to change that.
Let's consider your code step by step.
It seems you think that in this declaration
struct node *head, *tail = NULL; //Represent the head and tail of the doubly linked list
the both pointers head and tail are explicitly initialized by NULL. Actually only the pointer tail is explicitly initialized by NULL. The pointer head is initialized implicitly as a null pointer only due to placing the declaration in file scope. It to place such a declaration in a block scope then the pointer head will be uninitialized.
Instead you should write
struct node *head = NULL, *tail = NULL; //Represent the head and tail of the doubly linked list
Also it is a very bad approach when the functions depend on these global variables. In this case you will be unable to have more than one list in a program.
Also the declaration of the variable len that is used only in main as a global variable
int len;
also a bad idea. And moreover this declaration is redundant.
You need to define one more structure that will contain pointers head and tail as data members as for example
struct list
{
struct node *head;
struct node *tail;
};
The function addNode can invoke undefined behavior when a new node can not be allocated
void addNode(char data)
{
struct node *newNode = (struct node*) malloc(sizeof(struct node)); //Create new node
//...
You should check whether a node is allocated successfully and only in this case change its data members. And you should report the caller whether a node is created or not.
So the function should return an integer that will report an success or failure.
In the function remove_unique_dll after this while loop
while (next != NULL)
{
if (next->data == current->data)
{
cnt += 1;
next = next->next;
}
else
next = next->next;
//printf("#%c %d %c\n",next->data,cnt,current->data);
}
if cnt is equal to 1
if (cnt == 1)
//..
then the pointer next is equal to NULL. And using the pointer next after that like
if (prev == NULL)
{
head = next;
}
else
{
prev->next = next;
}
is wrong.
Also you need to check whether there is a preceding node with the same value as the value of the current node. Otherwise you can remove a node that is not a unique because after it there are no nodes with the same value.
And this statement
head = current;
does not make sense because after the outer while loop
while (current != NULL)
the pointer current is equal to NULL.
Pay attention that the function will be more useful for users if it will return the number of removed unique elements.
Here is a demonstration program that shows how the list and the function remove_unique_dll can be defined.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
char data;
struct node *next;
struct node *prev;
};
struct list
{
struct node *head;
struct node *tail;
};
int addNode( struct list *list, char data )
{
struct node *node = malloc( sizeof( *node ) );
int success = node != NULL;
if (success)
{
node->data = data;
node->next = NULL;
node->prev = list->tail;
if (list->head == NULL)
{
list->head = node;
}
else
{
list->tail->next = node;
}
list->tail = node;
}
return success;
}
size_t remove_unique_dll( struct list *list )
{
size_t removed = 0;
for ( struct node *current = list->head; current != NULL; )
{
struct node *prev = current->prev;
while (prev != NULL && prev->data != current->data)
{
prev = prev->prev;
}
if (prev == NULL)
{
// there is no preceding node with the same value
// so the current node is possibly unique
struct node *next = current->next;
while (next != NULL && next->data != current->data)
{
next = next->next;
}
if (next == NULL)
{
// the current node is indeed unique
struct node *to_delete = current;
if (current->prev != NULL)
{
current->prev->next = current->next;
}
else
{
list->head = current->next;
}
if (current->next != NULL)
{
current->next->prev = current->prev;
}
else
{
list->tail = current->prev;
}
current = current->next;
free( to_delete );
++removed;
}
else
{
current = current->next;
}
}
else
{
current = current->next;
}
}
return removed;
}
void display( const struct list *list )
{
for (const node *current = list->head; current != NULL; current = current->next)
{
printf( "%c<->", current->data );
}
puts( "null" );
}
int main()
{
struct list list = { .head = NULL, .tail = NULL };
const char *s = "aabc";
for (const char *p = s; *p != '\0'; ++p)
{
addNode( &list, *p );
}
printf( "Doubly linked list:\n" );
display( &list );
size_t removed = remove_unique_dll( &list );
printf( "There are removed %zu unique value(s) in the list.\n", removed );
printf( "Doubly linked list after removing unique elements:\n" );
display( &list );
}
The program output is
Doubly linked list:
a<->a<->b<->c<->null
There are removed 2 unique value(s) in the list.
Doubly linked list after removing unique elements:
a<->a<->null
You will need at least to write one more function that will free all the allocated memory when the list will not be required any more.

Every Node in my Linked List contain the final value - how to fix?

I'm a Noob, trying to read in a dictionary file that contains one word per line, i.e. one\n two\n three\n, and insert the items in order into a linked list. I believe my code is otherwise working, but right now, it's outputting three, three, three (instead of one, two, three). I now believe my error is in my print function, so need to figure out how to traverse the linked list and print out the various node values.
// code modified from https://www.geeksforgeeks.org/linked-list-set-2-inserting-a-node/
#include <stdio.h>
#include <stdlib.h>
// A linked list node
struct Node
{
const char *data;
struct Node *next;
};
/* Given a reference (pointer to pointer) to the head
of a list and an int, appends a new node at the end */
void append(struct Node** head_ref, const char *new_data)
{
/* 1. allocate node */
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
struct Node *last = *head_ref; /* 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 (*head_ref == NULL)
{
*head_ref = 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;
return;
}
// This function prints contents of linked list starting from head
void printList(struct Node *node)
{
while (node != NULL)
{
printf("%s\n", node->data);
node = node->next;
}
}
/* Driver program to test above functions*/
int main()
{
// set up a file point to File to be opened
FILE* fp;
// holds contents of each line/word - as 1 word per line in dictionary per specs
char buffer[255];
fp = fopen("Xs.txt", "r");
if (fp == NULL)
{
fprintf(stderr, "Could not open infile");
return 2;
}
/* create an empty list */
struct Node* head = NULL;
while(fgets(buffer, 255, (FILE*) fp)){
//printf("%s", buffer);
append(&head, buffer);
}
printList(head);
fclose(fp);
return 0;
}

How can I fix this error in c code for linked lists?

I am receiving an error on Xcode when for my delete function for a single linked list in c and at this point im not sure why. The error im receiving is
"malloc: * error for object 0x7ffeefbff5d8: pointer being freed was not allocated * set a breakpoint in malloc_error_break to debug"
int delete (node ** list, int delete)
{
node * current= *list;//declares current
//stop at node that is one before i will need to delete (in this case iam deleting the 2node)
if (*list != NULL)
{
node * temp= *list;
temp = temp->next;
free(list);
*list=temp;
}
while (current->next->data != delete)
{
current=current->next;
}
node * temp;//Declares temp
temp=current->next->next;
free(current->next);//one after current free'd
current->next=temp;
return 0;
}
There are number of things which is not clear or unnecessary
Why you want to free the free(list); list is double pointer, if you free this headpointer of linked list will loose. after delete operation How will print/access the list again if needed ?
list is the headpointer which is holding the link and you didn't allocated any memory for list in main() or calling function so you can't free it. thats why error is
pointer being freed was not allocated
If you want to free only then first you should do free(*list) and then free(list)
From your code segment
free(list); /* list is freed here */
*list=temp; /* How will you access again *list */
As per my thinking your if block should be
if (*list != NULL) {
node * temp= *list;
temp = temp->next; /* temp holds 2nd node address & you need that only */
}
First of all Your question was very unclear, for the next time please post all of the necessary code and explain the purpose of the function in a few line.
I guess what you are trying to do is to remove a specific item from a linked list according to the value of the parameter data.
From the site learn-c:
"
Removing a specific item
To remove a specific item from the list, either by its index from the beginning of the list or by its value, we will need to go over all the items, continuously looking ahead to find out if we've reached the node before the item we wish to remove. This is because we need to change the location to where the previous node points to as well.
Here is the algorithm:
Iterate to the node before the node we wish to delete
Save the node we wish to delete in a temporary pointer
Set the previous node's next pointer to point to the node after the node we wish to delete
Delete the node using the temporary pointer
There are a few edge cases we need to take care of, so make sure you understand the code. "
Then they posted the code, I think you should go there and read the entire post.
Good luck
Your code have a faulty logic plus obvious errors.
Once list is freed you have no right to access it again.
free(list);
*list=temp;
Managing the linked list is not difficult but it requires attention to details.
When you delete the node in the list you have a responsibility to connect the nodes.
If you delete the head you have a responsibility to move the head.
If the head is the node you are looking for and this is the only node in the list than after removal that node has to be marked as NULL.
The test program below uses struct node *find(struct node *start, int data) function to find a node which matches your criteria and uses delete to delete it. All edge cases have been taken care of.
#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;
// List structure
typedef struct list {
node* head; // The entry point into a linked list. If the list is empty then the head is a null reference.
} list;
// Create list
list* list_create()
{
list* new_list = malloc(sizeof(list));
if(new_list == NULL)
return NULL; // protection
new_list->head = NULL; // If the list is empty then the head is a null reference. no elements in the list
return new_list; // return created new list
}
// 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* prepend_node(list* in_list, node* new_node)
{
// Add item to the front of the in_list, return pointer to the prepended node (head)
if(in_list == NULL)
return NULL;
if(new_node == NULL) // problem, not enough memory
return NULL; // in_list->head has not changed
/*
new_node
|*| --> NULL
next
*/
if(in_list->head == NULL) // if list is empty
{
in_list->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 = in_list->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)
*/
in_list->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 in_list->head; // we are returning pinter to new_node
}
// Print out list
void print_list(list* in_list)
{
node* node;
if (in_list == NULL)
{
return;
}
if (in_list->head == NULL)
{
printf("List is empty!\n");
return;
}
printf("List: ");
node = in_list->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 p 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; // remember next
free(p);
printf("Head removed\n");
return 1;
}
else // the only node
{
free(p);
printf("Last node removed\n");
*start = 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() {
list* new_list = list_create();
node *n1 = node_new(1);
node *n2 = node_new(2);
node *n3 = node_new(3);
// list is empty
print_list(new_list);
prepend_node(new_list, n1);
prepend_node(new_list, n2);
prepend_node(new_list, n3);
// list has 3 elements
print_list(new_list);
delete(&new_list->head, 3);
print_list(new_list);
delete(&new_list->head, 1);
print_list(new_list);
delete(&new_list->head, 2);
// list has 2 elements
print_list(new_list);
printf("head: %p\n",new_list->head);
print_list(new_list);
free (new_list); // after deleting all elements, delete the list itself
return 0;
}
Output:
List is empty!
List: 3 2 1
Head removed
List: 2 1
List: 2
Last node removed
List is empty!
head: (nil)
List is empty!

insertion doesn't take place for bigger size strings

Below programme doesn’t work for bigger size strings , but it works properly for small strings.I am not sure why sortedInsert function is not taking full length of string.There is no string length constraint also being used in this programme.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
/* Link list node */
struct node
{
char* pattern;
struct node* next;
};
/* function to insert a new_node in a list. Note that this
* function expects a pointer to head_ref as this can modify the
* head of the input linked list (similar to push())*/
void sortedInsert(struct node** head_ref, struct node* new_node)
{
struct node* current;
/* Special case for the head end */
if (*head_ref == NULL || (strcmp((*head_ref)->pattern ,new_node->pattern)> 0))
{
new_node->next = *head_ref;
*head_ref = new_node;
}
else
{
/* Locate the node before the point of insertion */
current = *head_ref;
while (current->next!=NULL &&
strcmp(current->next->pattern, new_node->pattern)< 0)
{
current = current->next;
}
new_node->next = current->next;
current->next = new_node;
}
}
/* BELOW FUNCTIONS ARE JUST UTILITY TO TEST sortedInsert */
/* A utility function to create a new node */
struct node *newNode( char * pattern)
{
/* allocate node */
struct node* new_node =
(struct node*) malloc(sizeof(struct node));
new_node->pattern = (char *)malloc(sizeof(pattern));
/* put in the data */
strcpy(new_node->pattern , pattern);
new_node->next = NULL;
return new_node;
}
/* Function to print linked list */
void printList(struct node *head)
{
struct node *temp = head;
while(temp != NULL)
{
printf("\n%s", temp->pattern);
temp = temp->next;
}
}
/* Drier program to test count function*/
int main()
{
/* Start with the empty list */
struct node* head = NULL;
struct node* new_node = newNode("a.b.c.d.e.f.g.h.h.j.k.l.m.n.o");
sortedInsert(&head, new_node);
new_node = newNode("a.b.c.de.f.g.h.j.k.l.m.t.y.u.k");
sortedInsert(&head, new_node);
new_node = newNode("a.b.c.d.ef.g.h.h.k.j.l.y.u.l.p");
sortedInsert(&head, new_node);
printf("\n Created Linked List\n");
printList(head);
return 0;
}
Here is the output of above programme, where unexpected output can be seen.
Output:
Created Linked List
a.b.c.d.e.f.)
a.b.c.d.ef.g.h.h.k.j.l.y.u.l.p
a.b.c.de.f.g)
malloc(sizeof(pattern))
and then
strcpy(new_node->pattern , pattern); not correct.
better, use strlen() to get the received string length, then allocate memory, then perform strcpy() or memcpy() to copy the recived string.
Try with below code , it will work. you must pass string length instead of string itself
new_node->pattern = (char *)malloc(strlen(pattern)+1);
/* put in the data */
memcpy(new_node->pattern , pattern,strlen(pattern)+1);
Other answers are correct; however, there seems to be a dedicated function strdup to do what you want:
// Incorrect code
new_node->pattern = (char *)malloc(sizeof(pattern));
strcpy(new_node->pattern , pattern);
// Correct code, provided by user2083356
new_node->pattern = (char *)malloc(strlen(pattern)+1);
memcpy(new_node->pattern , pattern,strlen(pattern)+1);
// Does the same; seems easier to type and understand; also handles errors
new_node->pattern = strdup(pattern);

Printing contents of linked list only prints first node

This is the updated version of the code. i am trying to add some info in a link list every time a client sends a message to the server (it can be multiple clients). Every time a new message arrives, the function checks its time so it could add it to the list before or after the previous node depending on its current time. The server must print the messages in order of arrival. If there are equal time stamps then it should move to sort the equal ones in using the ids of the servers.
Here is my struct for the list:
'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;
the following is the function that inserts to list and sorts according to time:
void add_transaction (char* received_msg_IN, int curr_time_IN, u_int32_t my_id_IN, int elapsedIn)
{
/* Find the node with the smallest time >= curr_time_IN. 'found' starts as NULL, then
is always the node before 'cur'. 'cur' moves through the list until its time is
less than 'curr_time_IN'. So at the end, 'cur' is the first node that's too
far in, and 'found' is either NULL or the node we insert after. */
trade_list *newnode, *cur, *found;
found = NULL;
for (cur = head; cur && cur->sender_timer <= curr_time_IN; cur = cur->next)
found = cur;
if (found) {
/* If 'found' isn't NULL, we're inserting after it*/
/* Times match: Sort out in another way*/
} else {
newnode = malloc(sizeof(*newnode));
newnode->trader_msg = malloc(strlen(received_msg_IN)*sizeof(received_msg_IN));
strcpy(newnode->trader_msg,received_msg_IN);
newnode->sender_timer = curr_time_IN;
newnode->id_of_sender = my_id_IN;
newnode->local_time = elapsedIn;
newnode->next = found->next;
found->next = newnode;
}
} else {
/* No node with more recent time found -- inserting at 'head' */
newnode = malloc(sizeof(*newnode));
newnode->trader_msg = malloc(strlen(received_msg_IN)*sizeof(received_msg_IN));
strcpy(newnode->trader_msg,received_msg_IN);
newnode->sender_timer = curr_time_IN;
newnode->id_of_sender = my_id_IN;
newnode->local_time = elapsedIn;
newnode->next = head;
head = newnode;
}
EDITED AFTER NEW PROBLEM
I managed to sort the list using a sorting method instead later on. So now my list gets sorted just fine. It prints just fine swell, the new problem that arose now is that I want to delete the current node after I print it. So after it gets print it gets deleted. I used the following function but my app crashes.
void deletefirst (struct trade_list *head) {
struct trade_list *tmp = *head;
if (tmp == NULL) return;
*head = tmp->next;
free (tmp);
}
i call this function from my print function:
void print_trades()
{
trade_list * newnode = head;
while (newnode) {
if ((elapsed - newnode->local_time >= 8))
{
printf ("%s\n", newnode->trader_msg);
newnode = newnode->next;
deletefirst(newnode);
}
}
}
How would I delete the current node and move on?
The way you print the list should work fine, as long as there is at least one node. I'd recommend changing the do { ... } while() to just a while() { ... } though, so that it still works when the list is empty and head is NULL:
trade_list *currentnode = head;
while (currentnode) {
printf ("Trade: %s Time: %d ID: %d\n",
currentnode->trader_msg,
currentnode->sender_timer,
currentnode->id_of_sender);
currentnode = currentnode->next;
}
There are some problems with the way you add to the list, though. When head is not null, you're removing its link to the rest of your list:
if (head == NULL)
{
... /* skipped for brevity */
}
else
{
currentnode->next = NULL;
head = currentnode;
}
Since at this point currentnode == head, you're pointing head->next to NULL (if there were another node, you'd be throwing it away) and then assigning head to itself.
Your insertion code in general doesn't look right. If you want to insert only at the beginning of the list, you just need something like:
trade_list *newnode = malloc(sizeof(trade_list));
/* *** Fill out newnode's fields here *** */
newnode->next = head;
head = newnode;
If you want to insert after an arbitrary node, you have to find it first by walking the list, then do something like this (keeping later times at the head of the list):
trade_list *newnode, *cur, *found;
/* Find the node with the smallest time >= curr_time_IN. 'found' starts as NULL, then
is always the node before 'cur'. 'cur' moves through the list until its time is
less than 'curr_time_IN'. So at the end, 'cur' is the first node that's too far in,
and 'found' is either NULL or the node we insert after. */
found = NULL;
for (cur = head; cur && cur->sender_timer >= curr_time_IN; cur = cur->next)
found = cur;
if (found) {
/* If 'found' isn't NULL, we're inserting after it (or skipping if the times match,
since that seems to be what the original code was trying to do) */
if (found->sender_timer == curr_time_IN) {
/* Times match: skip it */
printf("SKIPPED\n");
} else {
/* inserting after 'found' */
newnode = malloc(sizeof(*newnode));
/* *** Fill out newnode's fields here *** */
newnode->next = found->next;
found->next = newnode;
}
} else {
/* No node with more recent time found -- inserting at 'head' */
newnode = malloc(sizeof(*newnode));
/* *** Fill out newnode's fields here *** */
newnode->next = head;
head = newnode;
}
Edited after comment:
To change the list to sort descending by time, then ascending by ID when the times match, just a couple of changes are needed.
Edit
Since the original for loop to find the node continues to the last node that meets the criteria, we just have to add a test into the loop to break when we're at the right one... that is, to break if the next node has equal time and a higher ID, since in that case we want to insert before it. (the earlier edit was flawed... sorry about that).
Additionally, the if (found->sender_timer == curr_time_IN) check afterwards is no longer needed, since there's no skipping and the sort by ID was handled by the new for loop.
So that section of code becomes:
/* original search */
for (cur = head; cur && cur->sender_timer >= curr_time_IN; cur = cur->next) {
/* *** added condition for ID sort */
if (cur->sender_timer == curr_time_IN && cur->id_of_sender >= my_id_IN) break;
found = cur;
}
if (found) {
/* If 'found' isn't NULL, we're inserting after it */
/* CHANGED: no need to skip when times are equal */
newnode = malloc(sizeof(*newnode));
/* *** Fill out newnode's fields here *** */
newnode->next = found->next;
found->next = newnode;
} else {
/* No node with more recent time found -- inserting at 'head' */
newnode = malloc(sizeof(*newnode));
/* *** Fill out newnode's fields here *** */
newnode->next = head;
head = newnode;
}
The problem is not with the printing code it is in the addition.
It looks like when adding a new node you allocate the node but does not connect it to the head or any of the other nodes.
You must have a code like this to add to the beginning of the list:
new_node->next = head;
head= new_node;
Also, the logic you used is obscured and you have many code duplications.
Adding to a linked list has only two options: beginning of the list (head) or on any of the other nodes, you do not need all this logic.

Resources