Doubly linked list c++ crashing after 3rd node - c++

So this is a doubly linked list that is supposed to hold names, address, and phone numbe and print them out. It works for the first 3 nodes then suddenly crashes after the the phone number entry on the third node. something is wrong with the pointers I believe but I have tried everything I can think of.
#include <iostream>
using namespace std;
class node
{
private:
string elem;
node* next;
node* prev;
string firstName;
string lastName;
string address;
string phoneNumber;
friend class linkedList;
};
//Linked list
class linkedList
{
public:
linkedList();
void addFrontNode(const string& e);
void addNode(const string& e);
void addNode2(node* nextloc, const string& e);
void addNode3(node* nextloc, const string& e);
void addNode4(node* nextloc, const string& e);
void print();
void search();
node* nextloc;
private:
node* head;
node* tail;
};
void linkedList::addFrontNode(const string &e)
{
node* v = new node;
string firstNameEntry;
string lastNameEntry;
string addressEntry;
string phoneNumberEntry;
cout << "Enter first name: ";
cin >> firstNameEntry;
cout << "Enter last name: ";
cin >> lastNameEntry;
cout << "Enter the address ";
cin.ignore();
getline(cin, addressEntry);
cout << "Enter a phone number ";
cin >> phoneNumberEntry;
v->elem = firstNameEntry;
v->lastName = lastNameEntry;
v->address = addressEntry;
v->phoneNumber = phoneNumberEntry;
v->next = head;
head = v;
}
void linkedList::addNode(const string &e)
{
node* v = new node;
string firstNameEntry;
string lastNameEntry;
string addressEntry;
string phoneNumberEntry;
cout << "Enter first name: ";
cin >> firstNameEntry;
cout << "Enter last name: ";
cin >> lastNameEntry;
cout << "Enter the address ";
cin.ignore();
getline(cin, addressEntry);
cout << "Enter a phone number ";
cin >> phoneNumberEntry;
v->elem = firstNameEntry;
v->lastName = lastNameEntry;
v->address = addressEntry;
v->phoneNumber = phoneNumberEntry;
v->next = tail;
tail = v;
tail->next = NULL;
}
void linkedList::addNode2(node* nextloc, const string &e)
{
node* v = new node;
string firstNameEntry;
string lastNameEntry;
string addressEntry;
string phoneNumberEntry;
cout << "Enter first name: ";
cin >> firstNameEntry;
cout << "Enter last name: ";
cin >> lastNameEntry;
cout << "Enter the address ";
cin.ignore();
getline(cin, addressEntry);
cout << "Enter a phone number ";
cin >> phoneNumberEntry;
v->elem = firstNameEntry;
v->lastName = lastNameEntry;
v->address = addressEntry;
v->phoneNumber = phoneNumberEntry;
nextloc = head -> next;
v->next = nextloc;
v->next = nextloc;
v->prev = nextloc->prev;
nextloc->prev = v;
}
void linkedList::addNode3(node* nextloc, const string &e)
{
node* v = new node;
string firstNameEntry;
string lastNameEntry;
string addressEntry;
string phoneNumberEntry;
cout << "Enter first name: ";
cin >> firstNameEntry;
cout << " Enter last name: ";
cin >> lastNameEntry;
cout << " Enter the address ";
cin.ignore();
getline(cin, addressEntry);
cout << " Enter a phone number ";
cin >> phoneNumberEntry;
v->elem = firstNameEntry;
v->lastName = lastNameEntry;
v->address = addressEntry;
v->phoneNumber = phoneNumberEntry;
v->next = nextloc;
v->prev = nextloc->prev;
nextloc->prev = v;
}
void linkedList::addNode4(node* nextloc, const string &e)
{
node* v = new node;
string firstNameEntry;
string lastNameEntry;
string addressEntry;
string phoneNumberEntry;
cout << "Enter first name: ";
cin >> firstNameEntry;
cout << " Enter last name: ";
cin >> lastNameEntry;
cout << " Enter the address ";
cin.ignore();
getline(cin, addressEntry);
cout << " Enter a phone number ";
cin >> phoneNumberEntry;
v->elem = firstNameEntry;
v->lastName = lastNameEntry;
v->address = addressEntry;
v->phoneNumber = phoneNumberEntry;
v->next = nextloc;
v->prev = nextloc->prev;
nextloc->prev->next = v;
nextloc->prev = v;
}
linkedList::linkedList() :head(NULL) {}
void linkedList::print()
{
node* v = new node;
v = head;
while (v != NULL)
{
cout << v->elem << " ";
cout << v->lastName << " ";
cout << v->address << " ";
cout << v->phoneNumber;
v = v->next;
}
}
void linkedList::search()
{
node* v = new node;
v = tail;
string lastNameSearch;
cout << "Enter a last name to search ";
cin >> lastNameSearch;
while (v != NULL)
{
if (v->lastName == lastNameSearch)
{
cout << v->elem;
cout << v->address;
cout << v->phoneNumber;
}
v = v->prev;
}
}
int main()
{
string node1;
string node2;
string node3;
string node31;
string node4;
string node5;
linkedList list;
list.addFrontNode(node1);
list.addNode(node2);
list.addNode2(list.nextloc, node3);
list.addNode3(list.nextloc, node4);
list.addNode4(list.nextloc, node5);
list.print();
return 0;
}

There are several issues.
If you use addFrontNode() to add first node, you must set your tail.
Change this:
v->next = head;
head = v;
To this:
v->next = NULL;
head = v;
tail = v;
Your function addNode() doesn't add to list correctly, try calling print and you will see, no node is added by this function.
Change this:
v->next = tail;
tail = v;
tail->next = NULL;
To this:
tail->next = v;
v->next = NULL;
tail = v;
In main() just use addFrontNode() to add first and then use addNode() to add all others. After this your code worked as expected.
Didn't understand meaning of variable nextloc, might be the source of problems.
Overall recommendation: create one function to add node

The code is indeed in need of re-write, but I don't want to repeat recommendations from the first answer. I however, believe that the question was about the reasons of the crash. It's because while copy-pasting the code, you added 2 extra lines to your addNode2:
void linkedList::addNode2(node* nextloc, const string &e)
{
...
nextloc = head -> next;
v->next = nextloc;
...
}
Comment out at least first of them and it won't crash any more (but this wouldn't make it better, really).

Related

I'm stuck on how to make a sorting algorithm in a doubly linked list using a person's first name and last name in C++

So I made a doubly linked list which stores a person's first name, last name, address and age and I am currently stuck on making a sorting algorithm for the list. So far I've managed to create 3 functions, one that adds a node to the list, one that deletes a node from the list and one which prints the list.
Here's what I have so far, the struct:
struct Node {
string First_Name;
string Last_Name;
string Address;
int age;
Node* next;
Node* prev;
} *first = 0, * last = 0;
The addToList function:
void addToList()
{
string temp = "Yes";
string First_Name;
string Last_Name;
string Address;
int age;
Node* current = first;
while (temp == "Yes") {
cout << "Enter the persons first name: ";
cin >> First_Name;
cout << "Enter the persons last name: ";
cin >> Last_Name;
cout << "Enter the persons age: ";
cin >> age;
cout << "Enter the persons address: ";
cin >> Address;
cout << "Would you like to add another person? Yes or No";
cin >> temp;
current = new Node;
current->First_Name = First_Name;
current->Last_Name = Last_Name;
current->age = age;
current->Address = Address;
if (last) last->next = current;
else first = current;
current->prev = last;
current->next = 0;
last = current;
}
return;
}
And the print list:
void printList()
{
if (!first)
{
cout << "Nothing is present in the list." << endl;
return;
}
Node* current = first;
while (current)
{
cout << current->First_Name << " " << current->Last_Name << " " << current->age << " " << current->Address << endl;
current = current->next;
}
}
My question is, how would I be able to sort the list alphabetically, I've never done sorting before...
Thank you!!
To use custom sorting for a doubly-linked list, overload operator<:
struct Person
{
std::string first;
std::string last;
std::string address;
unsigned int age;
bool operator<(const Person& p) const
{
bool is_less_than = false;
if (last == p.last)
{
is_less_than = first < p.first;
}
else
{
is_less_than = last < p.last;
}
return is_less_than;
}
};
Now you can use std::list and it will automatically sort by last name, then first. And std::list is a doubly-linked list.
To compare Persons:
Person a;
Person b;
//...
if (a < b)
{
std::cout << "Person A < Person B\n";
}

Can you check why removing an Item from a linked list is not working in this code? [duplicate]

This question already has an answer here:
How do I properly delete nodes of linked list in C++
(1 answer)
Closed 2 years ago.
I've been asked by a friend to help him with an exercise, basically the idea is like below.
Car number = fr50000 Car owner = AlexNelson Parking time = 3.5 hours.
He was told not to use stuff like string or getline, so it's simple app just to learn the idea of working with linked lists.
So I made this program. When I'm calling the remove() function the first time, it says the list is empty at the beginning (as it should do). But the second and third time, it's saying that the car is removed, but when I call the display() function, the car is still there (it didn't remove from the list)
Can you tell me what's wrong with my code?
#include <iostream>
using namespace std;
int length = 0;//variable of how many items in the list
struct node
{
char carNumber[15];
char carOwner[20];
float parkingTime;
node *link;
};
typedef struct node node;
node *head;//the begining of a list;
bool isempty()
{
if (length == 0)
return true;
else
return false;
}
void insert()
{
if (isempty())
{
head = new node;
cout << "Enter car number: ";
cin >> head->carNumber;
cout << "Enter Car owner: ";
cin >> head->carOwner;
cout << "Enter parking time: ";
cin >> head->parkingTime;
head->link = NULL;
length++;
}
else
{
node *p = head;
node *pnext = new node;
while (true)
{
if (p->link == NULL)
{
p->link = pnext;
break;
}
p = p->link;
}
cout << "Enter car number: ";
cin >> pnext->carNumber;
cout << "Enter Car owner: ";
cin >> pnext->carOwner;
cout << "Enter parking time: ";
cin >> pnext->parkingTime;
pnext->link = NULL;
length++;
}
}
void remove()
{
if (isempty())
{
cout << "List is empty\n";
return;
}
char carnumber[15];
cout << "Enter car number to remove: ";
cin >> carnumber;
node *p;
p = head;
while (p != NULL)
{
if (strcmp(p->carNumber, carnumber) == 0)
{
p = p->link;
cout << "Car removed\n";
return;
}
p = p->link;
}
cout << "Car was not found, check the number\n";
}
void display()
{
if (isempty())
{
cout << "List is empty\n";
return;
}
cout << "Car Number\t\tCar Owner\t\tParking Time\n";
node *p = head;
while (p != NULL)
{
cout << p->carNumber << "\t\t" << p->carOwner << "\t\t" << p->parkingTime << " Hours\n";
p = p->link;
}
}
int main()
{
string number;
display();
insert();
insert();
insert();
display();
remove();
display();
insert();
remove();
display();
}
Your remove() function is not actually removing (or destroying) a node from the list. You need to update the link of the previous node in the list to point to the next node in the list. And you need to update the head too, if removing the 1st node in the list.
Try this instead:
void remove()
{
if (isempty())
{
cout << "List is empty\n";
return;
}
char carnumber[15];
cout << "Enter car number to remove: ";
cin >> carnumber;
node *p = head;
node *prev = NULL;
while (p != NULL)
{
if (strcmp(p->carNumber, carnumber) == 0)
{
if (p == head)
head = p->link;
if (prev)
prev->link = p->link;
delete p;
cout << "Car removed\n";
return;
}
prev = p;
p = p->link;
}
cout << "Car was not found, check the number\n";
}
Alternatively:
void remove()
{
if (isempty())
{
cout << "List is empty\n";
return;
}
char carnumber[15];
cout << "Enter car number to remove: ";
cin >> carnumber;
node **p = &head;
while (*p != NULL)
{
if (strcmp((*p)->carNumber, carnumber) == 0)
{
node *n = *p;
*p = (*p)->link;
delete n;
cout << "Car removed\n";
return;
}
p = &(p->link);
}
cout << "Car was not found, check the number\n";
}
p = p->link; You're modifying the value of the local variable p, not the list. You need to modify the previous node's link field.
In the loop in remove, you are doing p = p->link, when p points to the node you want to remove. But you actually need to update the link field of the node that is pointing to p.
Here's a simple way of doing that:
node **p = &head;
while(*p)
if (strcmp((*p)->carNumber, carnumber) == 0)
break;
else p = &(*p)->link;
if (*p)
{
cout<<"Car removed\n";
delete std::exchange(*p, (*p)->link);
}
else cout << "Car was not found, check the number\n";
If you can't use std::exchange, then you can replace that with:
auto h = *p;
*p = (*p)->link);
delete h;

Program skips over std::getline [duplicate]

This question already has answers here:
Why does std::getline() skip input after a formatted extraction?
(5 answers)
Closed 6 years ago.
I have to design a program to allow the user to input information for 5 nodes in a doubly linked list and then sort the doubly linked list alphabetically. It skips over allowing the user to input the address, doesn't print any information besides the name ,and doesn't sort the list alphabetically. What am I doing wrong?
#include <iostream>
#include <string>
struct node
{
std::string firstName;
std::string lastName;
std::string address;
long phoneNum;
node *next;
node *prev;
};
bool isEmpty(node *head);
void insertAsFirstElement(node *&head, node *&last, std::string firstName, std::string lastName, std::string address, long phoneNum);
void insert(node *&head, node *&last, std::string firstName, std::string lastName, std::string address, long phoneNum);
void searchFor(node *&last, std::string lastName);
void showList(node *current);
bool isEmpty(node *head)
{
if(head == NULL)
return true;
else
return false;
}
void insertAsFirstElement(node *&head, node *&last, std::string firstName, std::string lastName, std::string address, long phoneNum)
{
node *temp = new node;
temp->firstName = firstName;
temp->lastName = lastName;
temp->address = address;
temp->phoneNum;
temp->next = NULL;
temp->prev = NULL;
head = temp;
last = temp;
}
void insert(node *&head, node *&last, std::string firstName, std::string lastName, std::string address, long phoneNum)
{
if(isEmpty(head))
insertAsFirstElement(head, last, firstName, lastName, address, phoneNum);
else
{
node *temp = new node;
temp->firstName = firstName;
temp->lastName = lastName;
temp->address = address;
temp->phoneNum;
int result = lastName.compare(last->lastName);
if (result < 0)
{
temp->next = head;
head->prev = temp;
temp->prev = NULL;
head = temp;
}
else if ( result > 0)
{
temp->next = NULL;
temp->prev = last;
last->next = temp;
last = temp;
}
}
}
void searchFor(node *&last, std::string findName)
{
node *temp = last;
while (temp != NULL)
{
if (temp->lastName == findName)
{
std::cout << temp->firstName << " " << temp->lastName << " " << temp->address << " " << temp->phoneNum << std::endl;;
}
temp = temp->prev;
}
}
void showList(node *current)
{
if(isEmpty(current))
std::cout << "The list is empty\n";
else
{
std::cout << "The list contains: \n";
while(current != NULL)
{
std::cout << current->firstName << " " << current->lastName << " " << current->address << " " << current->phoneNum << std::endl;
current = current->next;
}
}
}
int main()
{
node *head = NULL;
node *last = NULL;
std::string firstName;
std::string lastName;
std::string address;
long phoneNum;
int count;
count = 5;
while (count > 0)
{
std::cout << "Enter the first name of person #" << count << ":\n";
std::cin >> firstName;
std::cout << "Enter the last name of person #" << count << ":\n";
std::cin >> lastName;
std::cout << "Enter the address of person #" << count << ":\n";
std::getline(std::cin,address);
std::cout << "Enter the phone number of person #" << count << ":\n";
std::cin >> phoneNum;
insert(head, last, firstName, lastName, address, phoneNum);
count = count - 1;
}
showList(head);
std::string findName;
std::cout << "What is the last name of the person you would like to find?\n";
std::cin >> findName;
searchFor(last, findName);
return 0;
}
Your issue is that you are mixing cin >> and getline which is problematic in C++ due to trailing newlines and what not.
Good practice is to always use getline and then use a stringstream to split the line up into tokens. For example, I modified your solution to only use getline and string streams (NOTE: You need to #include <sstream> at the top of your file.
You can read more about the issues with mixing cin >> and getline and also other ways to solve them here.
int main()
{
node *head = NULL;
node *last = NULL;
std::string firstName;
std::string lastName;
std::string address;
std::string phoneNumStr;
long phoneNum;
int count;
count = 5;
while (count > 0)
{
std::cout << "Enter the first name of person #" << count << ":\n";
std::getline(std::cin,firstName); // no use of cin >>
std::cout << "Enter the last name of person #" << count << ":\n";
std::getline(std::cin,lastName); // no use of cin >>
std::cout << "Enter the address of person #" << count << ":\n";
std::getline(std::cin,address);
std::cout << "Enter the phone number of person #" << count << ":\n";
std::getline(std::cin,phoneNumStr);
std::stringstream s(phoneNumStr); // no use of cin. Using stringstream to break up line and extract it into phoneNum
s >> phoneNum;
insert(head, last, firstName, lastName, address, phoneNum);
count = count - 1;
}
showList(head);
std::string findName;
std::cout << "What is the last name of the person you would like to find?\n";
std::cin >> findName;
searchFor(last, findName);
return 0;
}

Linked List Not Working Properly

Here is my code
struct Node{
char* isbn;
char* author;
char* title;
char* copyright;
char* genre;
bool status;
Node* next;
};
struct LinkedList {
Node* head; // This is the starting pointer of Linked List
LinkedList(){
head = NULL;
}
void insertAtHead(char* a, char* b, char* c, char* d, char* e, bool f){
Node* temp = new Node;
temp->isbn = a;
// etc. assigning information
temp->next = head;
head = temp;
}
void display(){
int i = 1;
Node* it = head;
while (it != NULL){
// display book info
it = it->next;
i++;
}
cout << "\n";
}
};
int main(){
LinkedList LL;
int x;
char a1[10] = "";
char a2[25] = "";
char a3[25] = "";
char a4[15] = "";
char a5[15] = "";
bool a6 = 0;
do{
cout << "\n======================================\n";
cout << "1) Insert Book At Head.\n";
cout << "2) Display All Books.\n";
cout << "3) Exit.\n";
cout << "======================================\n";
cin >> x;
switch(x){
case 1:{
cout << "Enter ISBN: "; cin >> a1;
cout << "Enter The Author's Name: "; cin >> a2;
cout << "Enter The Book Title: "; cin >> a3;
cout << "Enter The CopyRights: "; cin >> a4;
cout << "Enter The Book Genre: "; cin >> a5;
cout << "Enter The Status Of Book: "; cin >> a6;
LL.insertAtHead(a1,a2,a3,a4,a5,a6);
break;
}
case 2:
LL.display();
break;
case 3:
break;
}
}while(x!=3);
return 0;
}
The Problem is That When i insert a book using case 1 of switch it inserts a book in
the linked list with the given data but when i enter a new book the previously saved book
is overwritten by new book
It's not the linked list which is not working. It's the way you assign the values. You givie it adress of your input buffers (which are overwritten at each reading) and you store this adress in your node.
You have to make a copy of your buffers (using the old C-way strdup()).
I'd suggest a better approach: consider the use of C++ strings.
It's suffichent to #include <string> and update your struct into:
struct Node{
string isbn;
string author;
string title;
string copyright;
string genre;
bool status;
Node* next;
};
As strings understand correctly the assignment from char*, it wll generate its own copy, not realying anymore on your buffers. It'll be better though to consider replacing char* with strings in all your code.

c++ LinkedList when calling display function

I"m trying to understand link list but every example I've tried to copy gives me a segmentation fault. This is my example program that I am working on.
in contacts.h
struct people{
string last;
string first;
int age;
people *next;
};
class Contacts {
private:
people *head;
public:
Contacts() {
head=NULL;
};
void add(string, string, int);
void display();
};
in main.cpp
//menu items
//cin >> option
//if option == 1, addContact
//if option == 8, displayContact
//basic in and out here no need to show code
in main.h
void addContact() {
Contacts *ptr;
int i, loop=0, a=0;
string l, f;
cout << "number of contacts " << endl;
cin >> loop;
for(i=0; i<loop; i++) {
cout << "enter last name ";
cin >> l;
cout << "enter first name ";
cin >> f;
cout << "enter age ";
cin >> a;
}
ptr->add(l,f,a);
}
void display() {
Contacts *ptr;
ptr->display();
}
in contacts.cpp
void Contacts::add(string l, string f, int a) {
people *node = new people;
node->last=l;
node->first=f;
node->age=a;
node->next=NULL;
}
void Contacts::display() {
people *tmp = head;
while(tmp!=NULL) {
cout << tmp->last << endl;
cout << tmp->first << endl;
cout << tmp->age << endl;
tmp->next;
}
the add function works
then display() gives me a segfault
Member function add should be defined the following way
void Contacts::add( const string &l, const string &f, int a )
{
head = new people { l, f, a, head };
}
Or if your compiler does not support initializer lists with the new operator then
void Contacts::add( const string &l, const string &f, int a )
{
people *p = new people;
p->last = l;
p->first = f;
p->age = a;
p->next = head;
head = p;
}
Member fuunction display should be declared as
void Contacts::display() const;
and defined as
void Contacts::display() const
{
for ( people *tmp = head; tmp; tmp = tmp->next )
{
cout << tmp->last << endl;
cout << tmp->first << endl;
cout << tmp->age << endl;
cout << endl;
}
}
The other two functions should be defined the following way
void addContact( Contacts &contacts )
{
int n = 0;
cout << "number of contacts " << endl;
cin >> n;
for ( int i = 0; i < n; i++ )
{
string l, f;
int a = 0;
cout << "enter last name ";
cin >> l;
cout << "enter first name ";
cin >> f;
cout << "enter age ";
cin >> a;
contacts.add( l, f, a );
}
}
void display( const Contacts &contacts )
{
contacts.display();
}
And in main you should define an object of type
Contacts contacts;
and use it as the argument of the functions above.