(C++) Getting inconsistent results while using Nodes/Linked Lists. - c++

#include <iostream>
#include <memory>
using namespace std;
struct Node
{
int data;
Node* next;
};
void append(Node*&, int);
void printList(Node*);
void insertNode(Node*&, int, int);
void searchList(Node*, int, int);
int main()
{
Node* head = nullptr;
int initialCount = -1, userInput, newNodeLoc = -1, newNodeVal, searchVal;
/// INITIALIZE LIST
while(initialCount <= 0)
{
cout<<"Enter the number of initial nodes (must be at least 1): ";
cin>>initialCount;
}
cout<<endl;
for(int i = 0;i<initialCount;i++)
{
cout<<"Enter a number: ";
cin>>userInput;
append(head,userInput);
}
cout<<endl;
cout<<"Here are the initial values in the linked list: "<<endl;
printList(head);
cout<<"\nEnter a number for a new node to insert to the linked list: ";
cin>>newNodeVal;
cout<<endl;
cout<<"Enter which position you want to insert it (ex. "<<head->data<<" is at pos 1): ";
cin>>newNodeLoc;
while((newNodeLoc<=0 || newNodeLoc>initialCount))
{
cout<<"New position must be greater than 1 and less than " << initialCount+1 <<": ";
cin>>newNodeLoc;
}
newNodeLoc--;
insertNode(head, newNodeVal, newNodeLoc);
cout<<"\nHere is the updated linked list: "<<endl;
printList(head);
/// SEARCH
cout<<"\nEnter the number that you want to search for in the list: ";
cin>>searchVal;
cout<<endl;
initialCount++;
cout<<initialCount;
searchList(head,searchVal,initialCount);
return 0;
}
void printList(Node* head)
{
Node *n = head;
cout<<n->data<<endl;
while(n->next != nullptr) // print out all nodes values'
{
cout << n->next->data<<endl;
n = n->next;
}
}
void append(Node*& head, int val)
{
Node* temp = new Node;
temp->data = val;
temp->next = nullptr;
Node* ptr = head;
if(head == nullptr) // check if list is empty
{
head = temp;
}
else
{
while(ptr->next != nullptr) // if list isn't empty, get to last element set it equal to temp
{
ptr = ptr->next;
}
if(ptr->next == nullptr)
{
ptr->next = temp;
}
}
delete temp;
temp = nullptr;
}
void insertNode(Node*& head, int val, int loc)
{
Node* temp = new Node;
Node* prevLoc = new Node;
Node* curr = head;
temp->data = val;
int tempPos = 0;
while(curr->next != nullptr && tempPos != loc)
{
prevLoc = curr;
curr = curr->next;
tempPos++;
}
prevLoc->next = temp;
temp->next = curr;
delete temp;
delete prevLoc;
curr = nullptr;
prevLoc = nullptr;
}
void searchList(Node* head, int sVal, int iCount)
{
Node* curr = head;
int index=0;
while(curr->next != nullptr && curr->next->data != sVal)
{
curr = curr->next;
index++;
}
cout<<index;
cout<<iCount;
if(index != iCount)
{
cout<<"Number found at index "<<index<<" in the linked list!";
}
if(index-1 == iCount)
cout<<"Number could not be found in this linked list.";
delete curr;
curr = nullptr;
}
Hi there! I'm trying to implement append/prntlist/insertnode/search functions and I'm getting extremely inconsistent compiling results. Sometimes the code will run fine. Sometimes the code will randomly break. Other times it'll print out numbers on an infinite loop. I'm thinking it's a memory leak somewhere (in append/print functions), but I'm not super confident. It might also be a loop that's breaking the code. Any and all help is appreciated! I understand that the search function doesn't work so you can ignore it. Thank you!

In your append():
delete temp;
temp is your new element, that you've just append()ed to the list. Now that it's a part of the list, it gets immediately deleted. Good-bye!
The next to the last element of your linked list now points to deleted memory. Subsequent attempt to walk the list results in undefined behavior. Subsequent attempts to append more elements to the list will just make things even worse, scribbling over deleteed memory (if it wasn't scribbled over anyway, by the next new) and generally making a major mess of everything.
The memory allocation logic in insert() is similarly flawed. It's even worse. Two news and two deletes. Furthermore, the overall logic is also wrong. Its ostensible purpose is to insert one more element to the list, so it shouldn't be allocating two new nodes, only one will do. Both append() and insert() add one more node to the list; so only one node needs to be newed in both cases.
But the overall problem is erroneous deletions of newed elements, when they should not be newed, and they continue to be used. You cannot use anything after it gets deleted. It's gone. It ceased to exist. It joined the choir-invisible. It's an ex-object. But the shown code erroneously deletes an element after it gets added to the link list and, ostensibly, is still logically a part of the link list.

Related

Circular linked list: Infinite loop

I'm trying to make a circular link list but i'm facing with a problem.
If i run the program with those 2 lines of code above, when i compile and run, it gets an infinite loop of cin if the number of elements is higher than 2. Without them works fine but it isn't anymore a circular linked list. Can you help ?
The problem is right here:
toPush->next = head;
head->pred = toPush;
Full code:
#include <iostream>
using namespace std;
typedef int data;
// Nodes
struct elements {
data value;
elements* next;
elements* pred;
};
// Function that pushes the element to the end
void insertElementEnding(elements* &head, data var) {
elements* toPush = new elements;
toPush->value = var;
toPush->next = NULL;
toPush->pred = NULL;
if(head == NULL) {
head = toPush;
} else {
elements* node = new elements;
node = head;
while(node->next != NULL) {
node = node->next;
}
node->next = toPush;
toPush->pred = node;
toPush->next = head;
head->pred = toPush;
}
}
// Function that prints the list
void showList(elements* head, int numbers) {
for(int i = 0; i < numbers && head != NULL; i++) {
cout << head->value;
head = head->next;
}
}
int main() {
elements* head = NULL;
int var, n;
cout << "Introduce the number of elements: ";
cin >> n;
for(int i = 0; i < n; i++) {
cin >> var;
insertElementEnding(head, var);
}
showList(head, n);
return 0;
}
Thanks in advance.
You need to look for the start of the loop, not NULL, ie
while(node->next != NULL)
should be
while(node->next != head)
As a sidenote, you should use nullptr instead of NULL in C++.
Also you have a memory leak in your program. You dont need to allocate new memory just to get a pointer for iterating your list. This right here is the problem:
elements* node = new elements;
node = head;
A better way would just be
elements* node = head;
First, validation for NULL makes sense only to check if the list is not initialized, before inserting the first element in it.
For all other cases it is redundant as the head should always have previous and following elements for the circle. In case it is just one in the least, it points to itself.
Then if you change the function slightly, it will resolve the problem
void insertElementEnding(elements* &head, data var) {
elements* toPush = new elements;
toPush->value = var;
if(head == NULL) {
head = toPush;
head->next = toPush;
head->pred = toPush;
} else {
// insert the new element before the head
head->pred->next = toPush;
head->pred = toPush;
}
}

segmentation fault only after accessing struct in linked list for a second time

Sorry for the unclear title, I really don't know how to describe this issue. I'm in my first year of computer science so I really don't know much about C++ yet. However, trying to look up this issue did not help.
The issue:
In the main function, the "printRawData" friend function is called twice. The function is supposed to print each element of the linked list stored by the the class "LinkedList". It works the first time, but the second time I get a segmentation fault. I really have no idea what I'm doing wrong. My T.A. said he thinks that the struct's string variable "element_name" is being corrupted when accessed.
Sorry for the messy code, if I'm not explaining my issue well, or if I'm breaking any kind of stackoverflow etiquette. I appreciate any help I get.
//Note: C++ 11 is needed, due to to_string use
#include <iostream>
#include <string>
using namespace std;
struct Node {
string element_name;
int element_count;
Node* next;
};
class LinkedList{
private:
Node* first;
public:
LinkedList();
~LinkedList();
bool isEmpty();
void AddData(string name, int count);
friend void printRawData(LinkedList l);
};
//where the error occurs
void printRawData(LinkedList l){
Node* n = l.first;
while (n != NULL) { //iterates through the linked list and prints each element
cout << n->element_name << " : " << n->element_count << endl;
n = n->next;
}
}
LinkedList::LinkedList(){
first = NULL;
}
LinkedList::~LinkedList(){
Node* n = first;
while (n != NULL) {
Node* temp = n;
n = temp->next;
delete temp;
}
}
bool LinkedList::isEmpty(){
return first == NULL;
}
void LinkedList::AddData(string name, int count){
Node* newnode = new Node;
newnode->element_name = name;
newnode->element_count = count;
newnode->next = NULL;
Node* n = first;
//if the linked list is empty
if(n == NULL){
first = newnode;
return;
}
//if there's only one element in the linked list,
//if the name of first element comes before the name of new element,
//first element's pointer is to the new element.
//otherwise, the new node becomes the first and points to the previous first
//element.
if (n->next == NULL){
if (n->element_name < newnode->element_name){
n->next = newnode;
return;
} else {
newnode->next = first;
first = newnode;
return;
}
}
//if the first element's name comes after the new element's name,
//have the new element replace the first and point to it.
if (n->element_name > newnode->element_name){
newnode->next = first;
first = newnode;
return;
}
//iterating through linked list until the next element's name comes after
//the one we're inserting, then inserting before it.
while (n->next != NULL) {
if (n->next->element_name > newnode->element_name){
newnode->next = n->next;
n->next = newnode;
return;
}
n = n->next;
}
//since no element name in the linked list comes after the new element,
//the node is put at the back of the linked list
n->next = newnode;
}
main(){
LinkedList stack;
stack.AddData("Fish", 12);
stack.AddData("Dog", 18);
stack.AddData("Cat", 6);
printRawData(stack);
printRawData(stack);
}
The function void printRawData(LinkedList l) passes the parameter by value, so it gets a copy of the LinkedList object.
However, the copy contains a copy of the first pointer, but doesn't copy any of the nodes. So when this copy is destroyed, the LinkedList destructor will delete all the nodes.
And then the original is damaged.
You might want to pass a reference instead of creating a copy.
This is also the reason why the std::list has copy constructors and assignment operators that perform a "deep copy", where the nodes are also copied (not just the list head).

trying to make a simpler insertion at end of linked list program.Help needed with minor issues

I have managed to create a simple insertion at beginnning of linked list program but now i am struggling with insertion at end of linked list.
The program seems to be able to take values from user but the output list is not coming correct.Could you help me out?
If possible keep along the lines of my program as i am beginner and won't be able to understand a completely different method.
Logic i used-
If list is empty then insert value at beginning else if list is not empty then travel along the list till the next value being pointed at is NULL and then enter the new value in place of NULL.
#include<iostream>
using namespace std;
struct node
{
int data;
node *next;
};
node *start=NULL;
void insertend(int x)
{
node* temp=new node;
if(start==NULL)
temp->data=x;
else
{
while(temp!=NULL)
{
temp=temp->next;
}
temp->next=x;
}
}
void display()
{
node* disp=new node;
while(disp!=NULL)
{
cout<<disp->data<<endl;
disp=disp->next;
}
}
int main()
{
int x;
char ch;
do
{
cout<<"Enter data";cin>>x;
cout<<endl;
insertend(x);
cout<<"Do you want to continue?(y/n)";cin>>ch;
cout<<endl;
}while(ch=='y');
cout<<"Your list:"<<endl;
display();
}
The entry point to your list is the variable start. But you never set it. Take for example the first item a user inputs. You will call insertend(), it will check that start == NULL, but then it never sets start. You must set start = temp or something similar. You have the same problem in the else section -- you loop through the nodes starting with temp, but you should be starting with start. And again in the function display(), you create a pointer to a node and start looping from it, but it will have no data -- you should use start as the starting point of your loop.
struct node{
int data;
node* next;
};
node *first = NULL, *last = NULL;
void insert(int x){
if(first == NULL){
first = new node;
first->data = x;
first->next = NULL;
}else if(last == NULL){
last = new node;
last->data = x;
first->next = last;
last->next = NULL;
}else{
node *n = new node;
n->data = x;
n->next = NULL;
last->next = n;
last = n;
}
}
As you can see I am keeping track of first and last node in the list. Insert function checks if there is anything in the list with if(first == NULL)part. If there isn't it creates the first node. Similar thing happens with the else if. Finally in the else block we create a new node with data x. Then point the node stored in variable last to our new node and set last to be that node.
Here is the display function:
void display()
{
node *disp =first;
while(disp->next != NULL){
cout << disp->data << " ";
disp = disp->next;
}
cout << disp->data;
}
I also recommend that you do a cleanup after your program is finished running since you are creating new nodes.
void cleanup(node* n)
{
if(n->next == NULL)return delete n;
cleanup(n->next);
delete n;
}
and then at the end of main call cleanup(first)
Hope this makes sense :) Have a nice day!

How to dynamically create new nodes in linked lists C++

Could anyone tell me if this is the basic idea of linked lists? What are the pros and cons to this method and what are best practices when implementing linked lists in C++? Im new to data structures so this is my first approach. If there is a better way to do this same thing, please let me know. Additionally, how would you create the nodes dynamically without hard coding it? Thanks.
#include <iostream>
#include <string>
using namespace std;
struct node {
int x;
node *next;
};
int main()
{
node *head;
node *traverser;
node *n = new node; // Create first node
node *t = new node; // create second node
head =n; //set head node as the first node in out list.
traverser = head; //we will first begin at the head node.
n->x = 12; //set date of first node.
n->next = t; // Create a link to the next node
t->x = 35; //define date of second node.
t->next = 0; //set pointer to null if this is the last node in the list.
if ( traverser != 0 ) { //Makes sure there is a place to start
while ( traverser->next != 0 ) {
cout<< traverser->x; //print out first data member
traverser = traverser->next; //move to next node
cout<< traverser->x; //print out second data member
}
}
traverser->next = new node; // Creates a node at the end of the list
traverser = traverser->next; // Points to that node
traverser->next = 0; // Prevents it from going any further
traverser->x = 42;
}
for tutorial purpose, you can work out this example:
#include <iostream>
using namespace std;
struct myList
{
int info;
myList* next;
};
int main()
{
//Creation part
myList *start, *ptr;
char ch = 'y';
int number;
start = new myList;
ptr = start;
while (ptr != NULL)
{
cout << "Enter no. ";
cin >> ptr->info;
cout << "Continue (y/n)? ";
cin >> ch;
if (ch == 'y')
{
ptr->next = new myList;
ptr = ptr->next;
}
else
{
ptr->next = NULL;
ptr = NULL;
}
}
//Traversal part begins
cout << "Let's start the list traversal!\n\n";
ptr = start;
while (ptr!=NULL)
{
cout << ptr->info << '\n';
ptr = ptr->next;
}
}
It allocates memory dynamically for as many elements as you want to add.
I'd prefer to make a linked list class. This eliminates the need to call 'new' more than once. A nice implementation with examples can be found here.
You are in fact already doing dynamic allocation. So, not sure what you are asking for. But if you want to define functions to add new nodes to your linked list (or delete a node etc.), this can be a probable solution:
The location nodes get inserted/deleted is dependent on the type of data-structure. In a queue, new nodes will get added to the end; at the top in case of a stack. A function that adds a node to the top, simulating STACK push operation:
void pushNode(node **head, int Value) {
node *newNode = new node;
newNode->x = Value;
newNode->next = *head;
*head = newNode;
}
It would be called like pushNode(&head, 15) where 'head' would be defined as node *head = NULL. The root head should initially be set to NULL. After this operation head will point to the newly added node (top of stack).
The approach would be very similar for other data-structures (viz. queues) and works fine. But as you are using C++, I would suggest to define a class for your linked-list and define these functions as methods. That way, it will be more convenient and less error-prone.
Even better use std::list. It's the standard thing, so much portable and robust than a custom implementation.
You can also do it in this way
#include <iostream>
using namespace std;
struct Node{
int data;
Node* next;
};
void createList(Node** head ,Node* temp){
int n;
char ch;
temp = *head;
while(temp != NULL){
cout<<"Enter The Value ";
cin>>temp->data;
cout<<"DO you want to continue(y/n)";
cin>>ch;
if(ch=='Y' || ch == 'y'){
temp->next = new Node;
temp = temp->next;
}else{
temp->next = NULL;
temp = NULL;
}
}
}
void ShowList(Node* head){
cout<<"your list :"<<endl;
while(head != NULL){
cout<<head->data<<" ";
head = head->next;
}
}
int main()
{
//Creation part
Node *head, *temp;
createList(&head,temp);
ShowList(head);
}

Inserting an integer at the end of the list and deleting at nth position

So, in my linked list program, what I want it to do is to ask the user how many numbers to input, and enter the numbers, and add those numbers at the end of the list. Then, it will print the list. After that, the user will choose a position of element in the list to delete and the list will be printed again.
#include <iostream>
using namespace std;
struct Node{
int data;
Node* link;
};
Node* head;
void Insert(int data){ //insert an integer at the end of the list
Node* temp = new Node();
Node* temp2 = new Node();
temp->data = data;
temp->link = NULL;
if(head = NULL){
head = temp;
return;
}
temp2 = head;
while(temp2->link != NULL){
temp2 = temp2->link;
}
temp2->link = temp;
}
void Delete(int n){ //delete an integer at nth position
Node* temp1 = new Node();
temp1 = head;
if(n == 1){ //if the first node is to be deleted
head = temp1->link; //now head points to second node
delete temp1; //delete first node
return;
}
for(int i = 0; i < n-2; i++){
temp1 = temp1->link; //temp1 points to (n-1)th node
}
Node* temp2 = temp1->link; //temp2 points to nth node
temp1->link = temp2->link; // pointing to (n+1)th node
delete temp2; //deleting nth node
}
void Print(){ //print out the list
Node* printNode = head;
cout << "List: ";
while(printNode != NULL){
cout << printNode->data;
cout << " ";
printNode = printNode->link;
}
cout << "\n";
}
int main(){
int x, count, n;
head = NULL; //start with an empty list
cout << "How many numbers? " << endl;
cin >> count;
for(int i = 0; i < count; i++){
cout << "Enter number: ";
cin >> x;
Insert(x);
}
Print();
cout << "Enter position to delete: ";
cin >> n;
Delete(n);
Print();
return 0;
}
After accepting the first number, the program stops working. Can I know where I did the code wrong and what can I do to make this code more efficient? Thanks in advance.
Big facepalm on my part, only a small mistake. Code has been corrected.
if(head == NULL){
head = temp;
return;
}
You might need to rethink your insertion function. The part that your code crashes on is during the while loop insertion. If you want temp2 to hold data then you need to dynamically allocate space for it which you did. However, you are just using it as a position indicator (to traverse the list) - so why do you need to allocate space just to point to head or any other nodes location in your list?
Here's how I would insert into the list (at the back of course):
void Insert(int data){ //insert an integer at the end of the list
Node* temp = new Node();
// This is to ensure that temp was created -> Also called defensive programming.
if (!temp)
{
cout << "We did not have enough space alloted to dynamically allocate a node!" << endl;
exit(1);
}
temp->data = data; // Bad nominclature for program; Don't use the same name twice.
temp->link = NULL;
if (head == NULL)
{
head = temp;
}
else
{
// This is to help traverse the linked list without having to
// manipulate the position of what head points to.
Node *Pos_Indicator = head;
while (Pos_Indicator->link != NULL)
{
Pos_Indicator = Pos_Indicator->link;
}
// We are at the end of the list, it is now safe to add.
Pos_Indicator->link = temp;
// Should probably have a check here for whether it was successful or not.
}
}
I was able to compile and run your code to completion with no other problems. Let me know if this helps!
EDIT: or you know (head = NULL) to (head == NULL) works too :(