Reference to non-NULL value NULL after assignment - c

I'm implementing a singly linked list using C.
struct Node
{
int nodeValue;
struct Node* pNext;
};
struct Node* head;
void createList()
{
head = (struct Node*)malloc(sizeof(struct Node));
}
void insertNodeAtBeginning(int value)
{
struct Node* newNode;
newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->nodeValue = value;
struct Node* auxNode;
if(head->pNext == NULL)
{
head->pNext = newNode;
}
else
{
auxNode = head->pNext;
head->pNext = newNode;
newNode->pNext = auxNode; //breakpoint set here
}
}
I've set a breakpoint on line marked by the comment. The value of auxNode is non-NULL:
(gdb) p auxNode
$4 = (struct Node *) 0x5555555551db <createList+18>
However the value of newNode->pNext to which the auxNode is assigned is NULL:
(gdb) p newNode->pNext
$5 = (struct Node *) 0x0
Could anyone clarify this behavior? Thanks.

For starters the function createList does not make a sense.
void createList()
{
head = (struct Node*)malloc(sizeof(struct Node));
}
You already created an empty list
struct Node* head;
Within the function data members nodeValue and pNext were not initialized,
The function insertNodeAtBeginning also does not make a sense because at least it does not insert a node at beginning due to this code snippet
if(head->pNext == NULL)
{
head->pNext = newNode;
}
Moreover it invokes undefined behavior because the data member pNext of the node pointed to by the pointer head was not initialized. And again you forgot to initialize the data member pNext of the new node when head->pNext is equal to NULL.
Remove the function createList and define the function insertNodeAtBeginning the following way
int insertNodeAtBeginning(int value)
{
struct Node* newNode = malloc( sizeof( struct Node ) );
int success = newNode != NULL;
if ( success )
{
newNode->nodeValue = value;
newNode->pNext = head;
head = newNode;
}
return success;
}

It appears that you want to maintain your head node, but insert between the head node and the node after the head node, correct? If that is the case, then aside from a misleading function name (perhaps insertNodeAfterHead would be more appropriate), you should initialize your head struct members after you allocate with malloc.
Should be...
void createList()
{
head = (struct Node*)malloc(sizeof(struct Node));
head->nodeValue = 0
head->pNext = NULL;
}

Related

Linked List: Insertion at beginning

I am a beginner in data structure and I recently wrote a code to insert a new node at the beginning of a linked list using functions but when I run it the inserted node doesn't get printed, please help me verify the error in my code and correct it
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node *next;
};
void
traversal(struct Node *ptr)
{
while (ptr != NULL) {
printf("%d\n", ptr->data);
ptr = ptr->next;
}
}
void
insert_first(struct Node *head, int data)
{
struct Node *ptr = (struct Node *) malloc(sizeof(struct Node));
ptr->data = data;
ptr->next = head;
head = ptr;
}
int
main()
{
struct Node *head;
struct Node *second;
struct Node *third;
struct Node *fourth;
head = (struct Node *) malloc(sizeof(struct Node));
second = (struct Node *) malloc(sizeof(struct Node));
third = (struct Node *) malloc(sizeof(struct Node));
fourth = (struct Node *) malloc(sizeof(struct Node));
head->data = 10;
head->next = second;
second->data = 20;
second->next = third;
third->data = 30;
third->next = fourth;
fourth->data = 40;
fourth->next = NULL;
traversal(head);
insert_first(head, 0);
printf("\n");
traversal(head);
return 0;
}
insert_first() function parameter head is a local variable of insert_first() function. So, the statement head = ptr; will make changes in local variable only. These changes will not reflect in the pointer you have passed as first argument to insert_first() function.
As stated in one of the comments that you can return the updated value of head of list and assign that value to original head pointer of list.
Another way could be to pass the address of head pointer of list to insert_first() function (in case, if you want to keep the void as return type of insert_first() function).
For this, you have to changes the type of head parameter of insert_first() function from struct Node * to struct Node ** (double pointer) and pass the address of head (i.e. &head) to insert_first() function. Dereferencing head parameter of insert_first() function will give you the original pointer whose address you have passed and then you can make it point to some other address.
Implementation:
void
insert_first(struct Node **head, int data)
{
struct Node *ptr = (struct Node *) malloc(sizeof(struct Node));
ptr->data = data;
ptr->next = *head;
*head = ptr;
}
and call it like this
insert_first(&head, 0);
^^^
A suggestion:
Follow good programming practise - always check the malloc() return.

How to fix casting a pointer to an integer?

I'm writing a program that creates a doubly linked list out of an array. Here's the code so far:
#include<stdio.h>
#include<stdlib.h>
struct Node {
int data;
struct Node *next;
struct Node *previous;
}
struct Node *create_dll_from_array(int array[], int x) {
int i;
struct Node *newNode, *temp, *head;
for (i=0; i<x; i++) {
newNode = (struct Node *)malloc(sizeof(struct Node));
newNode->data = *(array+i);
if (i=0) {
head = newNode;
temp = newNode;
newNode->next = NULL;
newNode->previous = NULL;
}
else {
*** temp->next = (struct Node*) newNode->data;
newNode->next = NULL;
*** newNode->previous = (struct Node*) temp->data;
temp = newNode;
}
}
return head;
}
int main(){
int array[5] = {11,2,7,22,4};
struct Node* head;
head = create_dll_from_array(array,5);
return 0;
}
So in the lines with ***, I'm getting the error: warning: cast to pointer from integer of different size
I don't know whether the program itself actually works, just asking about those two lines and why they aren't working. Thanks!
How to fix casting a pointer to an integer?
Don't assign an int to a pointer and then the need for casting is gone.
Assign a pointer to a pointer.
// temp->next = (struct Node*) newNode->data;
temp->next = newNode;
You can improve on these things:
Always initialize your pointer with NULL. This will guard you against the pointer pointing to an invalid address.
Do not hard code the array size value. Calculate it.
In the if condition you have used assignment =. Change that to equality check ==. If you will not do this, your program will crash.
just asking about those two lines and why they aren't working
It is because, temp->next points to a memory location of type struct node. You cant assign it an integer value (as you were doing). I have reproduced your full code below some of your lines commented.
#include<stdio.h>
#include<stdlib.h>
struct Node {
int data;
struct Node *next;
struct Node *previous;
};
struct Node *create_dll_from_array(int array[], int x) {
int i;
// struct Node *newNode, *temp, *head;
struct Node *newNode= NULL, *temp=NULL, *head=NULL;
for (i=0; i<x; i++) {
newNode = (struct Node *)malloc(sizeof(struct Node));
newNode->data = *(array+i);
// if (i=0) { Its wrong
if (i==0) {
head = newNode;
temp = newNode;
newNode->next = NULL;
newNode->previous = NULL;
}
else {
// temp->next = (struct Node*) newNode->data; // issue
temp->next = (struct Node*) newNode;
newNode->next = NULL;
// newNode->previous = (struct Node*) temp->data; //issue
newNode->previous = (struct Node*) temp; //issue
temp = newNode;
}
}
return head;
}
int main(){
// int array[5] = {11,2,7,22,4};
int array[] = {11,2,7,22,4};
struct Node* head;
// head = create_dll_from_array(array,5);
head = create_dll_from_array(array,sizeof(array)/sizeof(*array));
return 0;
}
Few more optimization that you can do is that inside your create_dll function, the if condition is hit only for the first time. You can move that to else condition and make your else condition your if condition

Linked List cursor won't go to the next node

I'm trying to create a Linked List in C, and I can't seem to figure out why my cursor won't go to the next node. I'm setting the current node to the next node, yet when I print out the cursor address, it's the same. I believe this is causing my to have a infinite loop, since that's my main problem. I'm setting the next pointer with:
orig_cursor = orig_cursor->next;
My entire method is below:
struct node* copyList()
{
if(!head)
return NULL;
struct node *head_copy = malloc(sizeof(struct node));
struct node *copy_cursor = head_copy;
struct node *orig_cursor = head;
head_copy->data = head->data;
head_copy->next = NULL;
if(orig_cursor->next)
{
while(orig_cursor)
{
copy_cursor->next = malloc(sizeof(struct node));
copy_cursor = copy_cursor->next;
printf("Original cursor pre-traversal = %d\n", orig_cursor->next);
orig_cursor = orig_cursor->next;
printf("Original cursor post-traversal = %d\n", orig_cursor->next);
copy_cursor->data = orig_cursor->data;
if(!orig_cursor->next)
{
copy_cursor->next = NULL;
break;
}
}
}
return head_copy;
}
I also use the following push() function to push nodes into the list:
void push(int data)
{
if(!head)
{
head = malloc(sizeof(struct node));
head->data = data;
head->next = NULL;
return;
}
struct node *new_node = malloc(sizeof(struct node));
new_node->data = data;
new_node->next = head;
head = new_node;
}
Try using
struct node * new_node = malloc(sizeof(struct node));

Why does this function not successfully insert a node into a linked list?

The function is supposed to insert a node to a linked list, but it has a bug and inserted nodes do not show up in the linked list. Where is the bug?
int insert(struct Node *headList, int payload) {
struct Node *newNode;
newNode = malloc(sizeof(struct Node));
assert (newNode != NULL);
newNode->payload = payload;
newNode->next = headList;
headList = newNode;
return 0;
}
I'm pretty sure that Node *headList is passed by value, because headList does not change outside this function, but I'm not sure how to fix this. Do I need a pointer to a pointer or something?
This function modifies the struct Node that this pointer points to:
int insert(struct Node *headList, int payload) {
...
headList = newNode;
...
}
however to modify the pointer itself, you need to pass an address of pointer to initialize pointer to pointer:
int insert(struct Node **headList, int payload) {
...
*headList = newNode; // <-- modifies the pointer itself
...
}
or alternatively you might handle this using the return value since return 0 seems a bit useless.
I don't see any use of return statement so instead of going with pointer to pointer, return updated headList pointer to caller
struct Node * insert(struct Node *headList, int payload) {
struct Node *newNode;
newNode = malloc(sizeof(struct Node));
assert(newNode != NULL);
newNode->payload = payload;
newNode->next = headList;
headList = newNode;
return headList;
}
//in caller function
//Some code
headList = insert(headList,100);
If you are very specific about the return statement go with pointer to pointer
int insert(struct Node **headList, int payload) {
struct Node *newNode;
newNode = malloc(sizeof(struct Node));
assert (newNode != NULL);
newNode->payload = payload;
newNode->next = headList;
*headList = newNode;
return 0;
}
//in caller function
//Some code
status = insert(&headList,100);

Syntax for pointer to pointer when passing to parameters (in C) [duplicate]

This question already has answers here:
pointer to a pointer in a linked list
(2 answers)
Closed 9 years ago.
Yesterday I was trying to implement a linked list and although it worked and I "sort of" understand, it fried my brain a little bit.
What is wrong with function addNode() here?
#include <stdio.h>
struct Node
{
int value;
struct Node *next;
};
struct Node *createList();
void addNode(struct Node* head, int value); // Adds Node directly after head
void viewList(struct Node *head); // Outputs list starting from head
int main()
{
struct Node *head = createList();
addNode(head, 10);
addNode(head, 8);
addNode(head, 23);
addNode(head, 5);
addNode(head, 4);
addNode(head, 4100);
viewList(head); // I didn't upload here to save space
return 0;
}
struct Node *createList()
{
struct Node *head = (struct Node *) malloc(sizeof(struct Node));
head = NULL;
return head;
}
void addNode(struct Node* head, int value)
{
if(head == NULL)
{
struct Node *tmp = (struct Node *) malloc(sizeof(struct Node));
tmp->value = value;
tmp->next = head;
head = tmp;
}
else
{
struct Node *newNode = (struct Node *) malloc(sizeof(struct Node));
newNode->value = value;
newNode->next = head;
head = newNode;
}
}
The reason I am confused is because that version of add node did not work whilst this one did...
void addNode(struct Node** head, int value)
{
if(*head == NULL)
{
struct Node *tmp = (struct Node *) malloc(sizeof(struct Node));
tmp->value = value;
tmp->next = *head;
*head = tmp;
}
else
{
struct Node *newNode = (struct Node *) malloc(sizeof(struct Node));
newNode->value = value;
newNode->next = *head;
*head = newNode;
}
}
and that was called in the main function using an amperand in front of the head node pointer
addNode(&head, 10);
The thing that also baffles me is this. I have written some practise functions that accepts a pointer in the parameter list and within the function, modifies what the pointer is pointing to. I never had to use this **pointer syntax.
It has to do with that parameters are passed by value. So in the first, non-working version, the pointer to head is passed by value so the variable is a local variable inside the function. Changes to local variables are not visible outside the function when the function returns.
However, in the second version you pass the pointer by reference, so the function knows where in memory the actual pointer is and can store directly in that memory.
ASCII-diagram time:
Lets say you have the following three variables:
int value1;
int *pointer1 = &value1;
int **pointer2 = &pointer1;
The memory for the variables look something like this:
+----------+ +----------+ +--------+
| pointer2 | --> | pointer1 | --> | value1 |
+----------+ +----------+ +--------+
So pointer2 points to pointer1, and pointer1 points to value1.
Using the dereference operator * on pointer2 will get the value of what pointer2 points to, i.e. pointer1.
Stylistic (don't repeat yourself) ::
void addNode(struct Node** head, int value)
{
if(*head == NULL)
{
struct Node *tmp = (struct Node *) malloc(sizeof(struct Node));
tmp->value = value;
tmp->next = *head;
*head = tmp;
}
else
{
struct Node *newNode = (struct Node *) malloc(sizeof(struct Node));
newNode->value = value;
newNode->next = *head;
*head = newNode;
}
}
You don't need the if/else ::
#include <stdlib.h>
void addNode(struct Node **head, int value)
{
struct Node *newNode = malloc(sizeof *newNode);
if ( !newNode) { error(); return;}
newNode->value = value;
newNode->next = *head; // Could be NULL, but we need a NULL anyway in that case
*head = newNode;
}
This here will not work well
struct Node *createList()
{
struct Node *head = (struct Node *) malloc(sizeof(struct Node));
head = NULL;
return head;
}
after you allocate a node and have head pointing to it you set head to point to NULL.
Here it is:
You have a bug with createList
struct Node *createList()
{
struct Node *head = malloc(sizeof(*head));
head->value = 0; //< Probably you want this
head->next = NULL; //< You definitively wanted this
return head;
}
If you are adding nodes to the tail of the list, then addNode would look like:
void addNodeLast(struct Node* head, int value)
{
struct Node *tailNode;
struct Node *newNode;
newNode = malloc(sizeof(*newNode));
newNode->value = value;
newNode->next = NULL;
// Find the last node in the list
for (tailNode = head; tailNode->next; tailNode = tailNode->next);
tailNode->next = head->next;
}
If you are inserting nodes after the head:
void addNodeAfterHead(struct Node* head, int value)
{
struct Node *newNode;
newNode = malloc(sizeof(*newNode));
newNode->value = value;
newNode->next = head-next;
head->next = newNode;
}
If you are changing the head (making new head every time):
Node *addNodeNewHead(struct Node* head, int value)
{
struct Node *newNode;
newNode = malloc(sizeof(*newNode));
newNode->value = value;
newNode->next = head;
return newNode;
}
...
Node * head = createList();
head = addNodNewHead(head, 3);
head = addNodNewHead(head, 5);

Resources