Trivial linked list creation bug using for loop - c++

i am trying to create a single linked list using for loop. I end up creating an extra node with a zero value.
Below is my code:
node *insert(node *curPtr) {
node *temp = new node() // create a temp node
curPtr = temp;
for ( int i=1; i < 3; i++ ) {
temp->data = i;
temp->next = new node();
temp = temp->next;
}
return curPtr;
}
void printList(node *curPtr) {
while(curPtr) {
std::cout<<curPtr->data<<std::endl;
curPtr = curPtr->next;
}
}
I get the following output:
1
2
0
Whereas i am expecting
1
2
What do i need to change in my code?
Thanks

The problem here is that you are always making
temp->next = new node();
So, in the while loop of the printList function, there is an extra iteration showing a node that have not been assigned yet and -guess that due a compiler assumption or because you are initializing the value of node.data in the constructor of node- you are getting a value equal to 0 for this node. The quick solution is to change the print function as following:
void printList(node *curPtr) {
while (curPtr->next) {
std::cout << curPtr->data << std::endl;
curPtr = curPtr->next;
}
}
I will prefer to make curPtr->next = null until the moment that it will be a real node to insert at the end of the list.

Related

Why am I getting this runtime error: member access within null pointer of type 'Solution::node' (solution.cpp)

I was solving a question on leetcode 1409. Queries on a Permutation With Key, but I am getting this runtime error I don't know why. I am unable to debug this error.
Problem Statement:Given the array queries of positive integers between 1 and m, you have to process all queries[i] (from i=0 to i=queries.length-1) according to the following rules:
In the beginning, you have the permutation P=[1,2,3,...,m].
For the current i, find the position of queries[i] in the permutation P (indexing from 0) and then move this at the beginning of the permutation P. Notice that the position of queries[i] in P is the result for queries[i].
Return an array containing the result for the given queries.
My approach: I created a linkedlist to store the integers form 1 to m.
Then according to each query, I pass it to a function getpos() which returns the position of that query in the list and then updates it as per the directions given in problem statement.
This return value is then added to a result vector which is supposed to be the final answer after all queries are processed.
I have added comments to better understand my code
class Solution {
public:
struct node {
int data;
node* next = NULL;
};
node* addnode(node* head, int data) {
if(head == NULL) {
head = new node;
head->data = data;
}
else {
node* temp = head;
while(temp->next != NULL) { temp = temp->next; }
temp->data = data;
}
return head;
}
int getpos(node** head, int data) { //To get position of given query
int count = 0;
node* temp = *head;
node* prev;
while(temp->data != data) { //runtime error:member access within null pointer of type 'Solution::node' (solution.cpp); SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior prog_joined.cpp:32:21
prev = temp;
temp = temp->next;
count++;
}
prev->next = temp->next; //searched node deleted
temp->next = *head; //add the searched node to beginning of the list
*head = temp; //udapate head
return count; //we have position stored in count;
}
vector<int> processQueries(vector<int>& queries, int m) {
node* head = NULL;
for(int i=0;i<m;i++) { head = addnode(head,i+1); }
int n = queries.size();
vector<int> result;
for(int i=0;i<n;i++) { result.push_back(getpos(&head,queries[i])); }
return result;
}
};
Please debug and explain the cause of the error. I face many runtime errors which I fail to debug.
Your add_node function is bugged. Just take a deep breath and look at the code. add_node should allocate a node using new every time it is called. Ask yourself how many times and under what circumstances your version allocates a new node?
I'm sure you can see that your code only allocates a new node when head equals NULL, therefore it must be bugged.
Incidentally if you wanted a linked list why didn't you use std::list? You would have avoided the mistake you made.

How can I check each 3 elements of a singly linked list and then delete some of them?

So basically I have this assignment on my University that asks to make a sorted singly linked list and then make some methods on it. The one that I'm having trouble is: "create delete() function that checks the average of each triple elements and if it's lower than integer 'K' (which is a parameter of said function) deletes the first element of the triple or deletes second and last element of the triple if it's higher."
I already made a function/method that deletes a single element of the linked list.
void LinkedList::deleteElement(int a)
{
Node *temp = head;
Node *previousTemp = head;
while(temp != nullptr)
{
if(temp->value == a)
{
break;
}
else
{
previousTemp = temp;
temp = temp->next;
}
}
if(temp == nullptr)
{
cout << "Can't delete. Element not found." << endl;
}
else
{
cout << "\nDeleting element: " << temp->value << endl;
previousTemp->next = temp->next;
delete temp;
}
howMany--;
}
void Sznur::deleteTriple()
{
Node *first = head;
Node *second = first->next;
Node *third = second->next;
}
The task is written pretty hard to understand but for ex.:
int K=3
linkedList: 7,6,6,3,3,3,2,1,1,1,1
after running the function:
linkedList: 7,3,1,1,1,1
(7+6+6)/3 > K -> deletes 6 and 6
(3+3+3)/3 > K -> deltes second 3 and last 3
(2+1+1)/3 < K -> deletes 2
If the linkedList length is not dividable by 3 the last elements stay in their place.
Try something like this.
void tripleFunc(Node* head, int K)
{
Node* nodePtr = head; // nodePtr always points at the start of a new triple
while (true)
{
Node* first = nullptr;
Node* second = nullptr;
Node* third = nullptr;
first = nodePtr; // When taking the three elements out, remember to always check for a null pointer BEFORE accessing the element
if (first)
second = first->next;
if (second)
third = second->next;
if (third)
nodePtr = third->next; // Keep the nodePtr pointing at the start of the next triple
else
return; // Only happens if one or more of the previous ifs failed, which means that we don't have enough elements left for a full triple
if (calculateAverage(first, second, third) < K) // Make this function
{
deleteElement(first->value);
}
else
{
deleteElement(second->value);
deleteElement(third->value);
}
}
}
I haven't tested it though, so any possible bugs are left as an exercise to the reader to find and sort out. :)

Merging 2 linked lists and appending to the end of linked lists c++

I don't have much so far but I am trying to get the hang of using linked lists.
Struct:
struct Node
{
int value;
Node *next;
};
How can I add a node to the end of the list? I am just trying to take in a pointer for the head of a list and an int value to add in as a new node. When I try running what I have currently I get an exception.
void addNode(Node* head, int x)
{
Node* temp = new Node;
temp->data = x;
temp->next = NULL;
if(!head)
{
head = temp;
return;
}
else
{
Node* last = head;
while(last->next)
last=last->next;
last->next = temp;
}
}
I haven't really begun to work on merging the two lists. I just know that I need to take in 2 linked lists (or pointers to the head of 2 linked lists?) and then run through the lists for all the nodes.
E.G: Linked list 1 has 3 nodes: 4, 10, 20.
Linked List 2 has 4 nodes: 2, 5, 15, 60.
The merge list function would results in a new linked list with 2,4,5,10,15,20,60 as the nodes.
EDIT: In my main, I am calling the addNode function like so:
Node *head = new Node;
insertAtEnd(head,20);
Is that correct or could that be the cause of the exception?
By doing this:
void addNode(Node* head, int x)
// here ---------^
and then later this:
head = temp; // here
you're simply modifying the local head pointer, which took on the address value passed from the caller. Since head is not an actual reference to a pointer (it's just a pointer), the result is the caller's pointer passed as head remains unaltered. You never append your allocated node to your list, leak memory, it becomes a sad day...
Pass the pointer by reference instead. Fixing that, then fixing the invalid data member, which should actually be value and a pointer-to-pointer for walking the list to find the end, the result could look something like this:
#include <iostream>
struct Node
{
int value;
Node *next;
};
void addNode(Node*& head, int x)
{
Node **pp = &head;
while (*pp)
pp = &(*pp)->next;
*pp = new Node;
(*pp)->value = x;
(*pp)->next = nullptr;
}
void printList(const Node *head)
{
for (; head; head = head->next)
std::cout << head->value << ' ';
std::cout << '\n';
}
void freeList(Node *&head)
{
while (head)
{
Node *p = head;
head = p->next;
delete p;
}
}
int main()
{
Node *head = nullptr;
for (int i=1; i<=5; ++i)
addNode(head, i);
printList(head);
freeList(head);
}
Output
1 2 3 4 5
I leave the task of implementing an actual merge to you, but this should be enough to get you a manageable list up and running.
Update: From the OP's edited question:
Node *head = new Node;
insertAtEnd(head,20);
Apart from now-being a completely different named function, your node is default-initialized. In your case that means the resulting Node from new Node; has indeterminate values for both value and next. You're then passing that to your function, which assumes a determinate value (null) to terminate your loop.
This can be fixed any number of ways; the mechanics of the code above is one such way. There is no need to pre-allocate a head node in the first place if the list management code is of the understanding that NULL means no-list. Your addNode original post seemed to at-least-try to follow that mantra.
Declare the function the following way
void addNode( Node* &head, int x) ;
And instead of this code snippet
Node *head = new Node;
insertAtEnd(head,20);
You have to call the function the first time the following way
Node *head = nullptr; // or NULL
addNode(head,20);
Notice that there is no function with name insertAtEnd in your post. There is function addNode.:)
If you need to merge two lists then you can use this demonstrative program as a sample. Of course you will need to add some other functions as for example deleting lists that to get a complete project.
#include <iostream>
struct Node
{
int value;
Node *next;
};
Node * insert( Node *current, int value )
{
Node *tmp;
if ( current == nullptr )
{
tmp = new Node { value, nullptr };
}
else
{
tmp = new Node { value, current->next };
current->next = tmp;
}
return tmp;
}
std::ostream & display( Node *head,
std::ostream &os = std::cout,
const char *delimiter = " " )
{
for ( ; head; head = head->next ) os << head->value << delimiter;
return os;
}
Node * merge( Node * &head1, Node * &head2 )
{
Node *new_head = nullptr;
Node *current = nullptr;
while ( head1 != nullptr && head2 != nullptr )
{
Node *tmp;
if ( head2->value < head1->value )
{
tmp = head2;
head2 = head2->next;
}
else
{
tmp = head1;
head1 = head1->next;
}
tmp->next = nullptr;
if ( new_head == nullptr )
{
new_head = tmp;
current = new_head;
}
else
{
current->next = tmp;
current = current->next;
}
}
if ( head1 != nullptr ) new_head == nullptr ? new_head : current->next = head1;
if ( head2 != nullptr ) new_head == nullptr ? new_head : current->next = head2;
head2 = nullptr;
head1 = new_head;
return new_head;
}
int main()
{
Node *list1 = nullptr;
Node *list2 = nullptr;
list1 = insert( list1, 4 );
insert( insert( list1, 10 ), 20 );
display( list1, std::cout << "List1: " ) << std::endl;
list2 = insert( list2, 2 );
insert( insert( insert( list2, 5 ), 15 ), 60 );
display( list2, std::cout << "List2: " ) << std::endl;
std::cout << std::endl;
merge( list1, list2 );
display( list1, std::cout << "List1: " ) << std::endl;
display( list2, std::cout << "List2: " ) << std::endl;
return 0;
}
The program output is
List1: 4 10 20
List2: 2 5 15 60
List1: 2 4 5 10 15 20 60
List2:
this may be a cause of exception:
struct Node
{
int value; <----- Node structure has value property
Node *next;
};
Node* temp = new Node;
temp->data = x; <------ Assigning to data property of Node which does not exists
temp->next = NULL;
To add list you may use same approach
void addNode(Node* head, Node* head2)
{
Node* last = head;
while(last->next) last=last->next;
last->next = head2;
}
EDIT: In my main, I am calling the addNode function like so:
Node *head = new Node;
insertAtEnd(head,20);
This is wrong. You didn't initialize head->next, so within insertAtEnd the code while(last->next) last=last->next; will attempt to compare uninitialized pointer and if it isn't null, will dereference it. This will likely crash your program rather than throw an exception though. Then again, it's undefined behaviour, so anything may happen.
Since your insert function already covers the case of inserting to empty list, I would simply call
head = nullptr;
insertAtEnd(head,20)`;
Besides that, there's the bug of never updating the head pointer outside the function, which has already been covered in other answers.

Printing Linked List in C++

My following code print just only first element. In print_list() function, it stops after printing first element. It says after first element, head->next is 0. Shouldn't point towards second element?
I want to simply print whole list.
#include<iostream>
#include<cstdlib>
using namespace std;
struct node {
int x;
node *next;
};
node* add_element(node*);
bool is_empty(node*);
void print_list(node*);
node* search(node*);
int main()
{
node *head;
head=NULL;
node* current=head;
for(int i=0;i<5;i=i+1)
{
if (current==NULL)
{
current=add_element(current);
head=current;
}
else{
current=add_element(current);
}
}
cout<<head->next<<endl;
// DOUBT: head->next gives NULL value. It should give me pointer to 2nd node
print_list(head);
}
node* add_element(node* current)
{
node* temp;
temp=new node;
temp->next=NULL;
cout<<"enter element"<<endl;
cin>>temp->x;
current=temp;
return current;
}
bool is_empty(node* temp)
{
return temp==NULL;
}
void print_list(node* temp)
{
if (is_empty(temp)==false)
{
cout<<"here temp(head)"<<temp->next<<endl;
while(temp!=NULL)
{
cout<<temp->x<<endl;
temp = temp->next;
}
}
}
Print function print first element because you have just one node in the Linked List! Actually the mistake is present in add_element(node*) function, you overwrite address of head node with new node (so having memory leak) as I marked below:
node* add_element(node* current)
{
node* temp;
temp = new node; <---" You allocated memory"
temp->next = NULL; <---" Set next NULL"
cout<< "enter element" << endl;
cin>> temp->x; <---" Assign a value in new node"
// Replace below two line with suggested
current = temp; <---"MISTAKE: Overwrite first node"
"temp next is NULL so losing address of other nodes"
return current; <--- "return first node"
}
Next of new node (so first node) is NULL hence the print function prints only first node's value.
Suggestion:
You should Correct as follows to add new node as a first node in linked list:
temp -> next = current; // new nodes next if present first node
return temp; // new code becomes first node
Be careful current should be NULL initially.
With my suggestion in add_element() function also change the for loop code in main() as follows:
for(int i=0; i < 5; i = i + 1){
current = add_element(current);
}
head = current;
And check the working code at Codepade (instead of user input I added value using y = 100 variable).
Edit To append new node:
You need to check whether new node is first node of not (read comments).
// returns first node address in linked list = head
node* add_element(node* head){
node *temp, *new_nd;
// Create new node
new_nd = new node;
new_nd->next = NULL;
cout<<"enter element"<<endl;
cin>>new_nd->x;
// Is new node is the first node?
if(!head)
return new_nd;
// move to last
temp = head;
while(temp->next) temp = temp->next;
// add new node at last
temp->next = new_nd;
// return old head
return head;
}
Also simply main() as below:
int main(){
node *head = NULL;
for(int i = 0; i < 5; i = i + 1){
head = add_element(head);
}
print_list(head);
}
check this working code.
Your problem is here:
node* add_element(node* current)
{
node* temp; //You created a new node
temp=new node; //You allocated it here
temp->next=NULL; //You set its next property to null
cout<<"enter element"<<endl; //
cin>>temp->x;
current=temp; //This should be current->next = temp. You are overwriting it!
return current; //And now you are returning essentially the temp object that
//You created and you set its next property to NULL
}
You are assigning the node you created in temp = new node to the current node that was passed in. What you want to do is assign the node you just created to the current node's next property. It should be current->next = temp
head->next is NULL because you set it so in add_element(). To have a linked list, you should set current->next = temp.
As you're using C++, you might consider using std::list instead of implementing your own linked list.
if (current==NULL)
{ current=add_element(current);
head=current;
}
else
{ current->next=add_element(current);
current=current->next;
}
The correct code.
You have to make a small correction in the loop.
You have to add a new node and then make it point to the next of the current node.
so the simplified code is current->next=add_element(current)
and then make current point to the new current.

Single Sorted Linked List - Infinite Loop

I'm working with a single linked list and I want to sort it from lower to higher values of integer. I though I had the idea but then the execution enters in a infinite loop and I can't see clearly why. This is the part of the code I worked with:
class Node {
int data;
Node* next;
public:
Node() { };
void SetData(int aData) { data = aData; };
void SetNext(Node* aNext) { next = aNext; };
int Data() { return data; };
Node* Next() { return next; };
};
class List {
Node *head;
public:
List() { head = NULL; };
void Print();
void Append(int data);
void Delete(int data);
};
void List::Append(int data) {
// Create a new node
Node* newNode = new Node();
newNode->SetData(data);
newNode->SetNext(NULL);
// Create a temp pointer
Node *tmp = head;
if ( tmp != NULL ) {
// Nodes already present in the list
// Parse to end of list anytime the next data has lower value
while ( tmp->Next() != NULL && tmp->Next()->Data() <= newNode->Data() ) {
tmp = tmp->Next();
}
// Point the lower value node to the new node
tmp->SetNext(newNode);
newNode->SetNext(tmp->Next());
}
else {
// First node in the list
head = newNode;
}
}
void List::Print() {
// Temp pointer
Node *tmp = head;
// No nodes
if ( tmp == NULL ) {
cout << "EMPTY" << endl;
return;
}
// One node in the list
if ( tmp->Next() == NULL ) {
cout << tmp->Data();
cout << " --> ";
cout << "NULL" << endl;
}
else {
// Parse and print the list
do {
cout << tmp->Data();
cout << " --> ";
tmp = tmp->Next();
}
while ( tmp != NULL );
cout << "NULL" << endl;
}
}
I'm confused if the list increases infinitely or the error comes from the Print function...
Sorry for the, perhaps, dummy errors.
Thanks.
Your problem is these two lines:
tmp->SetNext(newNode);
newNode->SetNext(tmp->Next());
You should reverse them. Right now, you set tmp.next = newNode, and then newNode.next = tmp.next (= newNode), so newNode points to itself. Then traversing past newNode leads to an infinite loop.
You are failing to link two existing nodes properly. Look at this fragment of your code:
tmp->SetNext(newNode);
newNode->SetNext(tmp->Next());
If for example you have this list:
head -> 5
and you want to insert a node with number 4 you will have:
head -> 5 <- tmp
newNode -> 4
With tmp->SetNext(newNode)
head (and tmp) -> 5 -> 4 <- newNode
With newNode->SetNext(tmp->Next());
head (and tmp) -> 5 -> 4 <- newNode
So any attempt to iterate through the list will result in and infinite loop:
5
4
4
4
4 ...... forever
// Point the lower value node to the new node
tmp->SetNext(newNode);
newNode->SetNext(tmp->Next());
Since you overwrite tmp->next in the first call, your second call is actually pointing newNode->next towards newNode itself, creating a cycle. This causes your infinite loop when calling Print ;-)
The solution is to do something like as follows...
Node* _next = tmp->Next();
tmp->SetNext(newNode);
newNode->SetNext(_next);
That being said, your code is still broken. The problems is that you don't check whether you need to place before the head of the list; try doing something as follows..
if ( tmp ) {
// Check whether to become new head
if ( tmp->Data() > newNode->Data() ) {
newNode->SetNext(tmp);
head = newNode;
}
else {
// Nodes already present in the list
// Parse to end of list anytime the next data has lower value
while ( tmp->Next() && tmp->Next()->Data() <= newNode->Data() ) {
tmp = tmp->Next();
}
// Point the lower value node to the new node
Node* _next = tmp->Next();
tmp->SetNext(newNode);
newNode->SetNext(_next);
}
}
else {
// First node in the list
head = newNode;
}
Side note: you can use an initializer list to rewrite code like...
List() : head(NULL) { };
In addition, if NULL is equivalent to 0, you can simplify conditions of the form X == NULL and X != NULL as merely X and !X, respectively.
See my ideone paste for the corrected version with an example.
int main() {
List l;
l.Append(15);
l.Append(40);
l.Append(7);
l.Print();
return 0;
}
... which produces
7 --> 15 --> 40 --> NULL