linked list undefined behavior - c

An abstract question: Say I have a singly-linked list of the nodes:
#node 1 #node 2
root->[data|next]->[data|next]->NULL
In C, root is declared:
struct Node *root = NULL;
where *root is the Node pointer 'holding' the address "NULL".
Now, lets say that I want to remove the last node in the linked list, the following code will allow the computer to do such action:
//pop: pop removes last/latter node in linked list and sets new last node to NULL
void pop(struct Node *root){
struct Node *last;
struct Node *current = root; //current point to same node as root
while(current->next != NULL){
if(current->next == NULL) {break;} //premature break in traversing of linked list; will stop at last node
last = current; //last points to same node as current
current = current->next; //move current to next node
}
last->next = NULL; //point second-to-last node to NULL, making it defacto last node in list
free(current); //free last node to heap
}//end pop
after calling pop and passing root to the function, the new linked list looks like this:
#node 1
root->[data|next]->NULL
If the program calls pop again, we should expect the linked list to look like this:
root->NULL
However, it does not! In the case of a linked list of integer elements in order, we will call pop until we observe strange behaviour:
List: 1 2 3
Call pop
List: 1 2
Call pop
List: 1
Call pop
List 1980765
The above is an example of undefined behavoir caused by a dangling pointer. Now the question is: How can the program avoid this behaviour and produce a side-effect that close to root->NULL from popping all nodes from the linked list until said list is empty?

First:
This condition can never ever be true:
if(current->next == NULL) {break;}
If it was true, we wouldn't reach that line but fall out of the while loop.
Second:
If you do not execute the body of the loop at least once, your pointer last keeps uninitialized. Hence
last->next = NULL;
sets a random memory location to NULL
Third:
When you try to remove the last remaining element, you need to free(root). But you cannot set root to NULL as it is passed by value.

Related

Linked list only prints out the last added member. What could be the mistake? [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 1 year ago.
Improve this question
I'm having a problem with a one way linked list. I'm trying to add elements to the end of the list(I guess it's FIFO arrangement) inside of a function (not passing elements one by one from the main function) so my idea was to save the position of the head pointer and create another pointer which would change positions every time I added an element.
The problem is that the head pointer's value also changes when I add a new element and I'm not sure why, because the only time I changed anything in regards to the head pointer is when I added the first element to the list. Then created the "current" pointer which I assigned to the head pointer and used from then on to add all other elements, but when I tried printing the head pointer value in each iteration of the while loop, it printed the last entered value (the value I wanted to assign to "current", not head).
When I try to print out the whole list, it only prints out the last element over and over.
Here's the code I've written:
typedef struct node NODE;
typedef struct node* PNODE;
struct node {
int info;
PNODE next;
};
void addToEnd(PNODE *head) {
PNODE newN = malloc(sizeof(NODE));
int num = 0;
printf("Type in the numbers. The loop ends when you type in -1.\n");
scanf("%d", &num);
getchar();
newN->info = num;
newN->next = NULL;
(*head) = newN;
PNODE current = *head;
while(1) {
scanf("%d", &num);
getchar();
if (num == -1) {
break;
}
newN->info = num;
newN->next = NULL;
if (current->next == NULL) {
current->next = newN;
current = current->next;
}
}
current = (*head);
while (current != NULL) {
printf("%d ", current->info);
current = current->next;
}
}
main() {
PNODE head = NULL;
addToEnd(&head);
}
The problem is that the head pointer's value also changes when I add a new element and I'm not sure why, because the only time I changed anything in regards to the head pointer is when I added the first element to the list.
By "the head node's value" I take you to mean (*head)->info (as opposed to *head).
It is true that you assign a value to *head only once, but you update the value of (*head)->info multiple times, as a result of *head, newN, and current all having the same (pointer) value. Observe:
(*head) = newN;
PNODE current = *head;
... *head is assigned the value of newN and current is assigned the value of *head; now these are all the same. Then ...
newN->info = num;
newN->next = NULL;
... current, newN, and *head are all still the same, so this sets the info and next members of the node to which they all point. Then, because current == newN, we know that current->next == newN->next, which was just set to NULL, so this is always executed:
if (current->next == NULL) {
current->next = newN;
current = current->next;
Moreover, because current and newN (and *head) are still equal, current->next = newN is equivalent to current->next = current, and of course, after that, current = current->next does not change the value of current or make it unequal to *head or newN. The three remain the same at all times throughout the input loop.
After that, of course ...
current = (*head);
... still leaves the three pointers all equal to each other. If at least one number was entered during the input loop then we also have current->next == current, so the print loop will print the last value entered over and over, until you kill the program.
In short, it's pretty much all wrong.
If you want to add elements to a list such that each one is appended at the end, then a reasonable way to proceed is this:
PREPARATION
Create a dummy NODE and assign *phead as the value of its next pointer. (Just declare a NODE normally; this one doesn't need to be dynamically allocated.)
Initialize current to point to the dummy node (current = &dummy).
Use a loop to advance current to point to the last node in the list (it will continue to point to dummy if the list is initially empty).
INPUT
Attempt to read a value. Break from the loop if none is presented; otherwise ...
Allocate a new NODE.
Assign the newly read value to the new node.
Update current->next to point to the new node.
Update current to point to the new node. (Do not do this before step 4!)
Go back to INPUT.1.
FINISHING UP
After loop termination, current points to the last node added. Set current->next to NULL to mark the end of the list.
Set *head = dummy->next. If the list was initially empty and at least one value was added, then this will assign *head to point to the head node. Otherwise, it will just copy the original value of *head back into it (see step PREPARATION.1).

Modifying LinkedList Through A Function

For my program, I need to create a function that accepts a linkedlist as a parameter, then deletes the first node from the list. There are other steps, but I'd like to get this sub-part done first.
This is what I have so far:
struct node *del_the_first(struct node *head) {
struct node *temp = head;
head = head->next;
temp->next = NULL;
return NULL;
}
I believe my solution is correct, however I have no way of testing it at this time. I'm more interested in why I am or am not wrong.
What you should test is:
print the value of temp at the end of the function,
this is what head was at the start of the function
print the value of head at the end of the function,
which is what the head of the list should be after returning for the function
print (from outside the function, e.g. from main) the value of the variable
which is supposed to point to the head of the list,
especially after deleting the first element
You will notice that outside your function the pointer to the head of the list is still pointing to where the first element still is.
You do not want that, do you? The variable which points to the head of the list is supposed to point to the second element of the list, isn't it?
If above is true, you probably want to use free() on the formerly first element of the list, before returning from the function.
Read this for more information on how to fix the first problem:
Parameter Passing in C - Pointers, Addresses, Aliases
Basically, you will want to return the new value of the pointer to the head of the list:
struct node *del_the_first(struct node *head)
{
struct node *temp = head;
head = head->next;
temp->next = NULL; /* not really needed */
free(temp);
return head;
}
Then call it like:
global_head = del_the_first(global_head);
Note that this code assumes that the list is not empty,
see the answer by ccpan on how to remove this assumption.
You need to check for boundary conditions. Suppose your linkedList is empty, then during runtime, you will get a segmentation fault. So you need to check if head pointer is NULL or not before trying to access next node.
Also, I don't know why you are returning a NULL. You are most probably wanting to return the new head node pointer.
struct node *del_the_first(struct node *head) {
if (head != NULL) {
struct node *temp = head;
head = head->next;
free(temp);
temp = NULL;
}
return head;
}

how to destroy a linked list in c?

i have this node :
typedef struct node {
DATA *dataa ;
struct node* next;
} *node_v;
with the asumption that i have already filled the linked list .. i want now to go over it and destroy it ..
i have made this function to destroy :
void destroyList(Node ptr) {
while(ptr) {
Node toDelete = ptr;
ptr = ptr->next;
free(toDelete);
}
}
it takes a node and free it . but my problem that each node i made the next points to NULL and the previous node points to the new node !
but the destroylist function does the opposite.. which means in order to deleate a node i call the function destroy list with the the last node i entered but then the toDeleate also points to it and the last node i enetred now points to the next node which in my case it is null , so i want to do the opposite.. any ideas of hiw i can do this !
like how can i make a destroy function that goes in the opposite direction !?
I call the function destroy list with the the last node I entered ... how can I make a destroy function that goes in the opposite direction?
With a singly-linked list, there is only one direction you can go, the direction in which the links are pointing. It sounds like the state of your list after building is something like:
pointer
|
V
firstVal -> secondVal -> thirdVal -> NULL
and you then call destroyList(pointer). That is not what you need for a singly-linked list. Such a list should maintain a head pointer to the start of the list, as follows:
pointer
|
V
firstVal -> secondVal -> thirdVal -> NULL
If you were to build your list like that, then your code for destroying the list would work just fine.
Since you haven't actually shown the code that builds the list (instead giving only a description of said list once built), that's most likely your problem.
In order to build the list correctly, you can use pseudo-code such as:
head = null
def append(head, tail, node):
node.next = null
if head == null:
head = node
tail = node
return
tail.next = node
tail = node

reversing a linked list in groups of a given size

I am solving a problem of reversing a linked list in groups of given size and the algorithm i am using is as follows:
1) Reverse the first sub-list of size k. While reversing i kept the track of the next node and previous node. Let the pointer to the next node be next and pointer to the previous node be prev & pointer to current node is ptr.
2) head = reverse(next, k)-Recursively call for rest of the list
3) return prev which is the new head of the reversed list
My code sample is:
struct node *reverse(struct node *start,int k)
{
struct node *prev,*ptr,*next;
prev=NULL;
ptr=start;
int count=0;
while(count<k && ptr!=NULL)
{
next=ptr->link;
ptr->link=prev;
prev=ptr;
ptr=next;
count++;
}
if(next!=NULL)//recursive call
start=reverse(next,k);
return prev;
}
But my output is only reversing the first half of the list!
for eg: If my list is : 98 74 94 857 8 7
My output is : 94 74 98(The rest is not being displayed)
Where am i wrong?..Is this method correct?
When you make the recursive call:
if(next!=NULL)//recursive call
start=reverse(next,k);
return prev;
you save the results of the recursive call in start, which you never refer to again. The pointer expires when control passes from the function, and the results of the recursive call (that is, anything beyond the first k elements) are lost. You must append these results to the reversed sub-list before returning.
if(next!=NULL)//recursive call
start->next=reverse(next,k);
return prev;
This would work next has stored location for the (k+1)th node.When we do start->next (k+1)th node becomes new head and

Pointers in c: Function which deletes every second element of linked list

I want to write a function which gets a pointer to a header of a linked list and deletes from the list every second member of it. The List is a linked elements of type element:
typedef struct element{
int num;
struct element* next;
}element;
I'm new to all these pointers arithmetic so I'm not sure I write it correctly:
void deletdscnds(element* head) {
element* curr;
head=head->next; //Skipping the dummy head//
while (head!=NULL) {
if (head->next==NULL)
return;
else {
curr=head;
head=head->next->next; //worst case I'll reach NULL and not a next of a null//
curr->next=head;
}
}
}
I kept changing it since I kept finding errors. Can you please point out any possible errors?
The algorithm is a lot simpler if you think of your linked list in terms of node pairs. Each iteration of your loop should process two nodes - head and head->next, and leave head equal to head->next->next upon exit. It is also important to not forget deleting the middle node, if you are cutting it out of the list, otherwise you are going to see memory leaks.
while (head && head->next) {
// Store a pointer to the item we're about to cut out
element *tmp = head->next;
// Skip the item we're cutting out
head->next = head->next->next;
// Prepare the head for the next iteration
head = head->next;
// Free the item that's no longer in the list
free(tmp);
}
It might be most straightforward to visualize this problem in recursive terms, like this:
// outside code calls this function; the other functions are considered private
void deletdscnds(element* head) {
delete_odd(head);
}
// for odd-numbered nodes; this won't delete the current node
void delete_odd(element* node) {
if (node == NULL)
return; // stop at the end of the list
// point this node to the node two after, if such a node exists
node->next = delete_even(node->next);
}
// for even-numbered nodes; this WILL delete the current node
void delete_even(element* node) {
if (node == NULL)
return NULL; // stop at the end of the list
// get the next node before you free the current one, so you avoid
// accessing memory that has already been freed
element* next = node->next;
// free the current node, that it's not needed anymore
free(node);
// repeat the process beginning with the next node
delete_odd(next);
// since the current node is now deleted, the previous node needs
// to know what the next node is so it can link up with it
return next;
}
For me, at least, this helps clarify what needs to be done at each step.
I wouldn't advise actually using this method because, in C, recursive algorithms may take up a lot of RAM and cause stack overflows with compilers that don't optimize them. Rather, dasblinkenlight's answer has the code that you should actually use.

Resources