Click here to Skip to main content
15,881,559 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Apologies to begin with if I am at the wrong forum, I know there are thousands of implementation of linkedlist already available on the internet, but I am looking at a place where I can discuss and see where am I going wrong with my specific implementation, so I can better my algorithmic thinking.

So I have just started learning DSA, and I am trying to implement a linkedlist. I have seen some tutorials and while the concept of linkedlist is fairly clear to me, I am facing problem with trying to implement a linkedlist.

I have written a piece of code according to my understanding of this data structure, but it doesn't seem to be working after the first element is added.

What I have tried:

C++
// LINKEDLIST
#include <stdio.h>
#include <stdlib.h>

struct Node {
	int data;
	struct Node* next_node;
};

struct Node* head_ptr = NULL; // linkedlist is empty initially

void addData(int val, struct Node* ptr_h) { // always head node will be passed to parameter
	struct Node* temp;

	if(ptr_h == NULL) {
		head_ptr = (struct Node*)malloc(sizeof(struct Node));
		temp = head_ptr;

		temp->data = val;
		temp->next_node = NULL;
	}
	else if(ptr_h != NULL) {
		temp = ptr_h;
		while(temp != NULL) {
			temp = temp->next_node;
		}
		temp = (struct Node*)malloc(sizeof(struct Node));
		temp->data = val;
		temp->next_node = NULL;
	}
}

int main(int argc, char const *argv[])
{
	addData(5, head_ptr);
	addData(7, head_ptr);
	addData(6, head_ptr);
	addData(6, head_ptr);

	int i = 0;
	struct Node* address = head_ptr;
	while(address != NULL) {
		i++;
		printf("%d\n", address->data);
		printf("%p\n", address->next_node);
		address = address->next_node;
	}
	printf("count is : %d\n", i);
	return 0;
}
I have written a function named addData() whose purpose is to add elements. I have a head pointerhead_ptr which I intend to always keep with me in order to have reference for the starting point of the linkedlist.

The logic is whenever addData() is called, it is checked whether the list is empty or is it already initialized (this is carried out by checking whether the head pointer references to NULL or not).
In the case if it references to NULL, some memory is dynamically allocated using malloc() and the head_ptr (which was initially assigned as NULL) is assigned this address. This is followed by assigning the data element of next node according to parameter passed through addData(), and the pointer element of the same next node is assigned as NULL signifying that the list ends there.
According to my understanding this much of code is working fine, because when I iterate through the list in the main(), it prints the first element.

I think the problem is in the following block of code, where if the head_ptr is not equal to NULL, a temporary variable temp is assigned its value and it is assigned the next address until it is not found to be NULL. After this, some memory is again dynamically allocate using malloc(), and its address is assigned to the temp variable, which is then used to set the data element of next node as the value passed through function parameter, and the pointer element of the same next node is set as NULL, signifying the list ends there.

In the main(), I am keeping a counter i=0, and iterating through the pointer, printing data and pointer element of each node. It prints the first element, but the pointer element points to NULL signifying that further elements once the first element is added was not added, and the variable i too is equal to 1 once the loop stops.

The output is as follows:
Terminal
5
(nil)
count is : 1
I have gone through the code multiple times, but unable to understand where am I going wrong, because to me it seems perfectly logical. I am expecting a sort of discussion, where you folks can help me move in a direction where I can see where am I going wrong.
Posted
Updated 7-Jan-23 1:19am
Comments
0x01AA 7-Jan-23 6:59am    
On a first glance:
In your addData you forgot to set next_node in the last existing item to the new added element.

First: You dont need to check else if(ptr_h != NULL). A simple else is enough.

Then the code in the else part should be:
else
{
   temp= ptr_h;
   while(temp->next_node != NULL)
   {
      temp= temp->next_node;
   }
   // At this point, temp points to the last existing element.
   temp->next_node= (struct Node*)malloc(sizeof(struct Node));
   temp->next_node->data = val;
   temp->next_node->next_node = NULL;
}

Btw. I would use new instead of malloc

I hope I'm not wrong and that it helps.
 
Share this answer
 
v3
Comments
Shobhit_23 7-Jan-23 7:57am    
Thanks for the help, the linkedlist is working as expected now, but I have two queries.
1) Isn't it better to use else if, as it makes the logic more explicit? Is there any performance difference of one over the other?
2) How is "new" superior to malloc(), although I am using C not C++ so can't use new here, but still why is new preferred over malloc() when it is available?
0x01AA 7-Jan-23 8:08am    
You are very welcome.
1) You checked allready for '== NULL'. For me it confuses more if you check again for '!= NULL'.
2) Because your original code fragment shows 'C++' I assumed you are working with 'C++'. Now I recognize you are working with 'C'. Then of course you are on the right path with 'malloc'. Sorry for that confusion.

[Edit]
An additional comment to 1)
If a test for equal fails, it can only be unequal. Therefore testing again for unequal - at least for me - makes no sense and does confuse.
I hope it helps ;)

[Edit1]
Quote: ' Is there any performance difference of one over the other?'
I don't think so. I would assume that today's compilers will optimize that 'double check' anyway.

CPallini 7-Jan-23 9:47am    
5.
0x01AA 7-Jan-23 9:49am    
Thank you very much Sir ;)
0x01AA is right, you forgot to add the newly created node to the list.
Moreover, you need to update the 'head' pointer, at first insertion. Try, for instance:
C
void addData(int val, struct Node ** pphead)
{
  struct Node * temp = *pphead;

  if ( ! temp )
  {
    temp = (struct Node *) malloc(sizeof (*temp));
    temp->data = val;
    temp->next_node = NULL;
    *pphead = temp;
  }
  else
  {
    // here temp != NULL
    while (temp->next_node)
    {
      temp = temp->next_node;
    }

    temp->next_node = (struct Node *) malloc(sizeof(*temp));
    temp->next_node->data = val;
    temp->next_node->next_node = NULL;
  }
}

int main(int argc, char const *argv[])
{
  addData(5, &head_ptr);
  addData(7, &head_ptr);
  addData(6, &head_ptr);
  addData(6, &head_ptr);
//...


[update]
If you don't want to pass the 'little intimidating' double pointer, the you might change the code this way
C
struct Node * addData(int val, struct Node * phead)
{
  struct Node * temp = phead;

  if ( ! temp )
  {
    temp = (struct Node *) malloc(sizeof (*temp));
    if ( temp ) // malloc may fail
    {
      temp->data = val;
      temp->next_node = NULL;
    }
  }
  else
  {
    // here temp != NULL
    while (temp->next_node)
    {
      temp = temp->next_node;
    }

    temp->next_node = (struct Node *) malloc(sizeof(*temp));
    temp = temp->next_node;
    if ( temp ) // malloc may fail
    {
      temp->data = val;
      temp->next_node = NULL;
    }
  }
  return temp; // return the newly added node
}

int main(int argc, char const *argv[])
{
  head_ptr = addData(5, NULL); // initialize head at very first call
  addData(7, head_ptr);
  addData(6, head_ptr);
  addData(6, head_ptr);
  //...
[/update]
 
Share this answer
 
v3
Comments
0x01AA 7-Jan-23 7:24am    
I'm too lazy to go trough all this code. From experience here, I would say you code is perfect. A 5.
CPallini 7-Jan-23 10:11am    
Thank you!
Shobhit_23 7-Jan-23 8:01am    
Thanks for the help I get it now, although it feels a little intimidating to use pointer to pointer. On a side note I am already updating the head_ptr on first insertion.

head_ptr = (struct Node*)malloc(sizeof(struct Node));
CPallini 7-Jan-23 10:10am    
With a small code modification, you can avoid the double pointer: see my updated solution.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900