Printing contents of linked list only prints first node - c

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.

Related

Does return; do anything in this function?

I'm trying to learn linked list following the instructions given in this tutorial and I can't seem to understand whether if the return; in the if statement at step 4 of the following code does anything...
/* 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, int 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; //<<<this return here
}
/* 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;
}
would the following be equally functional as the above if there was no return;statement like this?
/*4. If the Linked List is empty, then make the new node as head */
if(*head_ref == NULL)
{
*head_ref = new_node;
}
/*step 5*/
/*step 6*/
It does the same thing it does anywhere else, it exits from the function immediately.
If you don't return, you'll continue executing the function, but it won't work properly. The next block of code is:
while (last->next != NULL)
If that if was true, then last == NULL (because of the initialization last = *head). This code will try to indirect through the null pointer, which is undefined behavior.
There's no point in executing the rest of the code, which appends the new node after the last node in the list. The list was empty, so there's no last node to append to. You've already inserted it as the first node in the if block.
BTW, if is not a loop. A loop executes code repeatedly, and they're written using for and while. if is a conditional, it either executes the code once or it doesn't execute it at all.
Yes it changes the code flow. When the condition in 4 is true then *head_ref = new_node; is executed and the function then returns with no more processing.
If you take the return out then 5 and 6 will always be executed regardless of whether 4 is or not.
An alternative style (avoiding having a return in the middle of the function) would be to have an else for steps 5 and 6. Like the following:
/* 4. If the Linked List is empty, then make the new node as head */
if (*head_ref == NULL)
{
*head_ref = new_node;
}
else
{
/* 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;
}
Note there is no need to have the return at the last line as the function does not return a value.

Inserting node into sorted linked list in C

I need to insert a node into a sorted linked list. The list has a dummy node.
void add(Node **nodeArray, int setNumber) {
char userString[5];
Node *head = nodeArray[setNumber]; /* head pointer to first element of array (dummy) */
Node *newNode = malloc(sizeof(Node)); /* new node to be added to array */
Node *tmp = head;
printf("Please enter some data: ");
scanf("%s", userString);
strncpy(newNode->data, userString, DATA_SIZE); /* copies string entered by the user to data field of new node */
newNode->next = NULL; /* initializes next field of new node to NULL */
while (tmp->next)
tmp = tmp->next; /* points head to next element in list */
tmp->next = newNode; /* adds element to list */
}
This inserts a node at the end of the list. I understand the logic of the added sort. You look ahead to the next node and if the new node is less than the next, you point the new node to the next node and the previous node to the new node. Can someone help me implement this in code. This is what I have so far, but does not work.
if (!tmp->next)
tmp->next = newNode;
else {
while (tmp->next) {
if (strcmpa((tmp->next)->data, newNode->data) < 0) {
newNode->next = tmp->next;
tmp->next = newNode;
} //else if (strcmpa((tmp->next)->data, newNode->data) > 0) {
//tmp->next = newNode;
//}
tmp = tmp->next;
}
}
Here is the compare function:
int strcmpa(char *s1, char *s2) {
while (*s1 && tolower(*s1) == tolower(*s2))
{
s1++;
s2++;
}
return tolower(*s1) - tolower(*s2);
}
You're almost there but tmp->next should be redirected to newNode itself, not to newNode->next. Actually, that's a no-operation, because at the time of that command, newNode->next is what tmp->next was and you're reassigning a value that's already there.
What you want is that tmp, having pointed to X, points to next instead, which then only points to X. So, formally,
X = tmp->next;
tmp->next = newNode;
newNode->next = X;
which can be condensed to
newNode->next = tmp->next; /* using the X where originally stored */
tmp->next = newNode; /* rewriting that memory has to wait till now */
Update: The above code links newNode after tmp (as I thought that was what you needed). But in the sorted list, you find the first tmp that needs to appear after your node, so you need to go before that. This brings two problems:
You need to modify what the item before tmp points to, because the new node will go there, so you need to keep one more variable,
sometimes you'll need to put the new node in the very beginning, which has no previous node.
On the plus side, the above also handles !tmp->next (insertion at the end) gracefully so you don't really need another branch for that case.
It will look something like
Node* head = (whatever);
Node* prev = NULL;
Node* tmp;
for(tmp = head; tmp && strcmpa(tmp->data, newNode->data) < 0; tmp = tmp->next) {
prev = tmp;
}
/* now tmp points to the first larger node or to NULL and prev is its preceding node.
* If there's none (if the head is already larger) then prev = NULL. */
if(prev == NULL) {
newNode->next = head;
head = newNode; /* Don't forget to update this in the array where you took head from! */
} else {
newNode->next = prev->next;
prev->next = newNode;
}
This works also if head was NULL and creates a linked list with a single entry.
This focused on the insertion. Regarding the rest of your code (originally posted as comments):
The program will fail if you overrun the userString buffer on the unrestricted %s scanf. Set a limit.
With a limit, you don't need the unsafe strncpy. Use a normal strcpy that guarantees it will null-terminate your string.
Your strcmpa looks fine. But do make sure tolower() does what you expect it to with an input of '\0'. This compares the strings correctly:
char toLower(char in) {
if(in >= 'A' && in <= 'Z')
return in + 'a' - 'A';
else
return in;
}

Add duplicate items(string) in doubly linked list

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 )

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

Swap adjacent element in a linked list

While seeing a programming interview site, I came across code which swap adjacent elements in a linked list, but I found it to be a bit wrong. Below is the code.
void swap (struct list **list1)
{
struct list *cur, *tmp, *next;
cur = *list1;
if (cur && cur->next)
*list1 = cur->next;
//To make sure that we have at least two more elements to be swapped.
while (cur && cur->next)
{
next = cur->next;
tmp = next->next;
next->next = cur;
//We have to make 1->next as 4 in above example (figure).
if (tmp)
cur->next = tmp->next;
cur = tmp;
}
return;
}
Now for me, the condition if (temp) is not right here. Is that assessment correct?
Suppose we do have a linked list like:
1->2->3->4->NULL
Now our objective is to make a linked list like:
2->1->4->3->NULL
My worry is if the if (temp) is there in our code, we can't assign null at end of the linked list.
You are right. This doesn't work. It creates a loop at the end of the list, and if you run swap twice on the same list, the second run will get into an endless loop.
To fix this awkward code, replace the if (tmp) with the following code:
if(tmp)
if (tmp->next)
cur->next = tmp->next;
else
cur->next = tmp; // take care of an add number of nodes
else
cur->next = NULL; // take care of an even number of nodes
It will take care of the last nodes:
If there's an even number of nodes, it makes sure the last points to NULL instead of the node before it.
If there's an odd number of nodes, checking cur->next will prevent the following iteration, so the last node must be pointed by the one before it before the loop is exited.
It tests it to make sure it's not NULL (the last element). Not testing it will make your program follow the NULL pointer for the last element of the list.
tmp = next->next; /* If `next` is the last, `next->next` is NULL. */
Yes, you are right that there's a bug in the function - cur->next isn't updated correctly in all cases.
I personally find the local variable names tmp and next not particularly helpful and actively confusing in the case of next. Those names make it hard for me to keep track in my head of what's going on as I read through the function.
I find that the names node1, node2, and node3 work better to for me to keep a mental picture of which node is being manipulated. I wouldn't be surprised if other people disagree, though.
Here's a reworked version of the function that I find more readable, and more importantly that I believe is correct.
void swap (struct list **head)
{
struct list *node1 = *head;
struct list *node2 = node1 ? node1->next : NULL;
// handle degenerate cases
if (!node2) {
// no elements or only one element on the list
// nothing to do...
return;
}
// fix-up list head to what will be the new first node on list
*head = node2;
// while there are at least 2 more elements to be swapped
while (node1 && node2) {
struct list* node3 = node2->next;
// get a pointer to the node that will be the remainder of the
// list after the remainder of the list is processed.
//
// This will be NULL, node3, or 'node4' depending on whether
// there are 0 , 1 or 2+ nodes following node1 and node2
struct list* remainder = (node3 && node3->next) ? node3->next : node3;
node1->next = remainder;
node2->next = node1;
// prepare pointers to the next two nodes to be swapped
node1 = node3;
node2 = node3 ? node3->next : NULL;
}
return;
}
Java Implementation
Given: 1->2->3->4->5->6
Logic
1. First - 1, Second - 2, Third 3
2. Second.next = first
3. First.next = Third.next depending on even or odd numbers update accordingly
public ListNode evenOddMerge(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode first = head;
ListNode second = first.next;
ListNode third = null;
head = second;
while (true) {
third = second.next;
second.next = first;
if (third == null || third.next == null) {
first.next = third;
break;
}
first.next = third.next;
first = third;
second = first.next;
}
return head;
}
Credits: Geeks for Geeks

Resources