Linked list appears backwards - c

I have a linked list that is coming out backwards. I appear to be adding elements to the back of the list, when I want to place them on the front.
My nodes appear as follows:
struct node{
int data;
struct node* next;};
Next I set the head and variables
int info,x,listLength;
struct node *head = NULL;
struct node *temp;
printf("How many nodes?\n");
scanf("%d",&listLength);
Now I prompt for a new entry in the list, and move along the nodes
for(x=1;x<=listLength;x++){
printf("Insert an X value for node %d\n",x);
scanf("%d",&info);
temp = (struct node*)malloc(sizeof(struct node));
temp->data = info;
temp->next = head;
head = temp;
}
Finally I output the results and free the memory space
while(temp!=NULL){
printf("WE GOT %d\n",temp->data);
temp = temp->next;
}
free(temp);
However, if I enter input for three nodes and enter 1,2 and then 3, the output is 3,2, then 1! How can I change this to make sure the nodes are being added to the right place?
Thanks in advance!

Your code is saying
temp->next = head;
head = temp;
So you are adding to the start of the list, not the end, so "reverse order" is correct.
To add to the end you either need to keep track of the last node you added (e.g. struct node tail), or you need to search from head through the next ptrs until next = null to find where to add the new node.
Also: why the free(temp) at the end? Since it is after while(temp != NULL) it means temp must equal null. Are you trying to free the whole list or what?

Your head pointer points to the last object, thats why you get the numbers 'backwards'.
input: 1, 2, 3
head[data: 3] (last thing temp pointed to) -> next[data: 2] -> next[data: 1] -> NULL

it is working correctly..you want to put new node in front of the list, right? after 1, you are adding so. so now the list will be: 2->1, and in the same way, 3->2->1

Related

Head keeps getting the same value as tail pointer in singly linked list

I'm trying to create a singly linked list with nodes containing two parameters. Whenever I enqueue another node using the tail pointer, the head pointer takes the same value as the new node.
I'm sure the pointers are pointing to the same memory location or something similar, but I'm not sure how to fix this.
struct node
{
struct process *p;
struct node *next;
}
struct node* head;
struct node* tail;
void enqueue(struct process* newProcess)
{
struct node *newNode = malloc(sizeof(struct node));
newNode->p = malloc(sizeof(struct process));
newNode->p = newProcess);
if(tail==NULL)
{
head = tail = newNode;
return;
}
tail = tail->next;
tail = newNode;
}
I'd like to use this function to be able to create a singly linked list with the head node pointing to the first element in the list and the tail node pointing to the last element in the list. The current code results in both variables representing the last element added.
Setting tail = tail->next is setting tail to null because it isn't set the first time around, and then both tail and head are immediately overwritten in the subsequent call.
There are some issues here. First, to fix your problem, replace the two last lines with:
tail = tail->next = newNode;
Also, consider this:
tail = tail->next;
tail = newNode;
What is the point of assigning a variable to a value if you reassign the same variable in the next statement? You have the same error earlier on too:
newNode->p = malloc(sizeof(struct process));
newNode->p = newProcess;
Because of the second line, the only thing you achieve with the first line is a memory leak. Remove the first line completely.

Understanding code for creating a singly linked list using double pointer in C

I am trying to understand how the code below for creating a singly linked list works using a double pointer.
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node* next;
};
void push(struct Node** headRef, int data) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = *headRef;
*headRef = newNode;
}
//Function to implement linked list from a given set of keys using local references
struct Node* constructList(int keys[], int n) {
struct Node *head = NULL;
struct Node **lastPtrRef = &head;
int i, j;
for(i = 0; i < n; i++) {
push(lastPtrRef, keys[i]);
lastPtrRef = &((*lastPtrRef)->next); //this line
if((*lastPtrRef) == NULL) {
printf("YES\n");
}
}
return head;
}
int main() {
int keys[] = {1, 2, 3, 4};
int n = sizeof(keys)/sizeof(keys[0]);
//points to the head node of the linked list
struct Node* head = NULL;
head = constructList(keys, n); //construct the linked list
struct Node *temp = head;
while(temp != NULL) { //print the linked list
printf(" %d -> ", temp->data);
temp = temp->next;
}
}
I understand the purpose of using the double pointer in the function push(), it allows you to change what the pointer headRef is pointing to inside the function. However in the function constructList(), I don't understand how the following line works:
lastPtrRef = &((*lastPtrRef)->next);
Initially lastPtrRef would be pointing to head which points to NULL. In the first call to push(), within the for loop in constructList(), the value that head points to is changed (it points to the new node containing the value 1). So after the first call to push(), lastPtrRef will be pointing to head which points to a node with the value of 1. However, afterwards the following line is executed:
lastPtrRef = &((*lastPtrRef)->next);
Whereby lastPtrRef is given the address of whatever is pointed to by the next member of the newly added node. In this case, head->next is NULL.
I am not really sure what the purpose of changing lastPtrRef after the call to push(). If you want to build a linked list, don't you want lastPtrRef to have the address of the pointer which points to the node containing 1, since you want to push the next node (which will containing 2) onto the head of the list (which is 1)?
In the second call to push() in the for loop in constructList, we're passing in lastPtrRef which points to head->next (NULL) and the value 2. In push() the new node is created, containing the value 2, and newNode->next points to head->next which is NULL. headRef in push gets changed so that it points to newNode (which contains 2).
Maybe I'm understanding the code wrong, but it seems that by changing what lastPtrRef points to, the node containing 1 is getting disregarded. I don't see how the linked list is created if we change the address lastPtrRef holds.
I would really appreciate any insights as to how this code works. Thank you.
This uses a technique called forward-chaining, and I believe you already understand that (using a pointer-to-pointer to forward-chain a linked list construction).
This implementation is made confusing by the simple fact that the push function seems like it would be designed to stuff items on the head of a list, but in this example, it's stuffing them on the tail. So how does it do it?
The part that is important to understand is this seemingly trivial little statement in push:
newNode->next = *headRef
That may not seem important, but I assure you it is. The function push, in this case, does grave injustice to what this function really does. In reality it is more of a generic insert. Some fact about that function
It accepts a pointer-to-pointer headRef as an argument, as well as some data to put in to the linked list being managed.
After allocating a new node and saving the data within, it sets the new node's next pointer to whatever value is currently stored in the dereferenced headRef pointer-to-pointer (so.. a pointer) That's what the line I mentioned above accomplishes.
It then stores the new node's address at the same place it just pulled the prior address from; i.e. *headRef
Interestingly, it has no return value (it is void) further making this somewhat confusing. Turns out it doesn't need one.
Upon returning to the caller, at first nothing may seem to have changed. lastPtrRef still points to some pointer (in fact the same pointer as before; it must, since it was passed by value to the function). But now that pointer points to the new node just allocated. Further, that new node's next pointer points to whatever was in *lastPtrRef before the function call (i.e. whatever value was in the pointer pointed to by lastPtrRef before the function call).
That's important. That is what that line of code enforces, That means if you invoke this with lastPtrRef addressing a pointer pointing to NULL (such as head on initial loop entry), that pointer will receive the new node, and the new node's next pointer will be NULL. If you then change the address in lastPtrRef to point to the next pointer of the last-inserted node (which points to NULL; we just covered that), and repeat the process, it will hang another node there, setting that node's next pointer to NULL, etc. With each iteration, lastPtrRef addresses the last-node's next pointer, which is always NULL.
That's how push is being used to construct a forward linked list. One final thought. What would you get for a linked list if you had this:
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node* next;
};
void push(struct Node** headRef, int data)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = *headRef;
*headRef = newNode;
}
int main()
{
//points to the head node of the linked list
struct Node* head = NULL;
push(&head, 1);
push(&head->next, 2);
push(&head->next, 3);
for (struct Node const *p = head; p; p = p->next)
printf("%p ==> %d\n", p, p->data);
}
This seemingly innocent example amplifies why I said push is more of a generic insert than anything else. This just populates the initial head node.
push(&head, 1);
Then this appends to that node by using the address of the new node's next pointer as the first argument, similar to what your constructList is doing, but without the lastPtrRef variable (we don't need it here):
push(&head->next, 2);
But then this:
push(&head->next, 3);
Hmmm. Same pointer address as the prior call, so what will it do? Hint: remember what that newNode->next = *headRef line does (I droned on about it forever; I hope something stuck).
The output of the program above is this (obviously the actual address values will be different, dependent to your instance and implementation):
0x100705950 ==> 1
0x10073da90 ==> 3
0x100740b90 ==> 2
Hope that helps.

Segfault when accessing next node in singly linked list

I'm trying to just reverse a singly linked list, but with a bit of a twist. Rather than having the pointer to the next node be the actual next node, it points to the pointer in that next node.
struct _Node
{
union
{
int n;
char c;
} val;
void *ptr; /* points to ptr variable in next node, not beginning */
int var;
};
typedef struct _Node Node;
I know how to reverse a normal singly linked list and I think I have the general idea of how to go about solving this one, but I'm getting a segfault when I'm trying to access head->ptrand I don't know why.
Node *reverse(Node *head)
{
Node * temp;
Node * prev = NULL;
while(head != NULL)
{
temp = head->ptr + 4; /* add 4 to pass union and get beginning of next node */
head->ptr = prev;
prev = head;
head = temp;
}
return prev;
}
Even if I try and access head->ptr without adding 4, I get a segfault.
The driver that I have for this code is only an object file, so I can't see how things are being called or anything of the sort. I'm either missing something blatantly obvious or there is an issue in the driver.
First, I'll show you a major problem in your code:
while (head) // is shorter than while(head != NULL)
{
// Where does the 4 come from?
// And even if: You have to substract it.
// so, definitively a bug:
// temp = head->ptr + 4; /* add 4 to pass union and get beginning of next node */
size_t offset_ptr = (char*)head->ptr - (char*)head;
// the line above should be moved out of the while loop.
temp = head->ptr - offset_ptr;
Anyways, your algorithm probably won't work as written. If you want to reverse stuff, you are gonna have to work backwards (which is non-trivial in single linked lists). There are two options:
count the elements, allocate an array, remember the pointers in that array and then reassign the next pointers.
create a temporary double linked list (actually you only need another single reversely linked list, because both lists together form a double linked list). Then walk again to copy the next pointer from your temporary list to the old list. Remember to free the temporary list prior to returning.
I tried your code and did some tweaking, well in my opinion your code had some logical error. Your pointers were overwritten again and again (jumping from one node to another and back: 1->2 , 2->1) which were leading to suspected memory leaks. Here, a working version of your code...
Node *reverse(Node *head)
{
Node *temp = 0;
//Re-ordering of your assignment statements
while (head) //No need for explicit head != NULL
{
//Here this line ensures that pointers are not overwritten
Node *next = (Node *)head->ptr; //Type casting from void * to Node *
head->ptr = temp;
temp = head;
head = next;
}
return temp;
}

How to skip nodes of starting in linked list

I am trying to work on pointers.
I am under a situation that i want to traverse the linked list after the second node(from third node).
I have the basic idea to traversing the linked list is:
while(temp!=NULL)
{
temp=temp->next;
}
So what i want is this linked list must start from third position. Could anyone please help me in preparing logic for that? I am not interested in any using any in-built functions.
I will use this logic in other application.
If your list is temp then temp is also the first element.
Then temp->next will be second element, and temp->next->next will be the third.
So if you write
temp = temp->next->next;
temp will be pointing to the third element and you can start your traverse from there.
Node *nth(Node *head, int nth){//nth : 0 origin
while(nth && head){
--nth;
head = head->next;
}
return head;
}
...
Node *third = nth(head, 2);

What more does the code need to delete a node from a linked list successfully?

I want to delete a given node from a linked list by the node's index number (serial number). So what I tried to do in my function is that, first I have taken the user input of the index number. Then I used two node type pointers temp and current. I started traversing the list with current and when the index number of the node matches with the user input, I tried to delete the node. So far it is correct. I am facing problem with the deletion logic. Here is the code I tried:
void delete_node(struct node **start,int index_no)
{
int counter=0;
struct node *temp, *current;
temp=(struct node *)malloc(sizeof(struct node));
current=(struct node *)malloc(sizeof(struct node));
current=*start;
while(current->next!=NULL)
{
counter++;
if(counter==index_no)
{
temp= current->next;
free(current);
/*I guess some code is missing here. Help me finding the logic.*/
}
else
{
printf("\n The index number is invalid!!");
}
}
}
The commented portion lacks the deletion logic.
Also, I have a feeling that this code is not space and time-efficient. If it is so, please suggest to a way to make it more compact.
Why are you allocating two nodes in the delete function, then leaking their memory? It seems they should be initialized to start or one of its successors.
You also need to update the next pointer in the previous element and potentially also the start (head) of the list if the removed element was the first (ie. index_no == 1).
You also have an off-by-one error where the final node can never be deleted, because only a node with a ->next pointer will be considered for deletion.
Suggested reading: A Tutorial on Pointers and Arrays in C.
Deleting from a linked list is actually:
find the pointer that points to us
(if found) make it point to our .next pointer instead
delete our node.
In order to change the pointer that points to us, we need a pointer to it: a pointer to pointer. Luckily the first argument already is a pointer to pointer, it presumably points to the head pointer that points to the first list item.
struct node
{
struct node *next;
int num;
} ;
void delete(struct node **pp, int num) {
struct node *del;
int counter;
for (counter=0; *pp; pp= &(*pp)->next) {
if(counter++ == num) break;
}
if (!*pp) { printf("Couldn't find the node(%d)\n", num); return; }
/* if we get here, *pp points to the pointer that points to our current node */
del = *pp;
*pp = del->next;
free(del);
}

Resources