Why is this function causing a crash? (Multilist) - c++

I'm working on my first multilist and it has been nothing but a nightmare so far. Right now, I am allowing the user to place the x,y spots (class_number,student_number) in on their own. My node looks like this:
typedef struct node {
int student_number;
int class_number;
struct node* classpointer;
struct node* studentpointer;
}* nodePtr;
Initialized with
List::List() {
head = nullptr;
currClass = nullptr;
currStudent = nullptr;
}
To add in the data values and set up pointers I have two functions.
void List::addNodeToClass() {
nodePtr n = new node;
n->classpointer = NULL;
cout << "What class number would you like to add?" << endl;
int x;
cin >> x;
n->class_number = x;
if(head != NULL) {
currClass = head;
while (currClass->classpointer != NULL) {
currClass = currClass->classpointer;
}
currClass->classpointer = n;
}
else {
head = n;
}
}
And
void List::addNodeToStudent() {
nodePtr n = new node;
n->studentpointer = NULL;
cout << "What student number would you like to add?" << endl;
int x;
cin >> x;
n->student_number = x;
if(head != NULL) {
currStudent = head;
while (currStudent->studentpointer != NULL) {
currStudent = currStudent->studentpointer;
}
currStudent->studentpointer = n;
}
else {
head = n;
}
}
I make function calls to both of these functions in my menu() function, and in main() I only call for menu()
int menu() {
int input;
List List;
while (input != 3) {
cout << " " << endl;
cout << "Press '1' to input a node" << endl;
cout << "Press '2' to view the list of nodes" << endl;
cout << "Press '3' to exit" << endl;
cout << " " << endl;
cin >> input;
if (input == 1) {
List.addNodeToClass();
List.addNodeToStudent();
}
else if (input == 2) {
List.PrintList();
}
else if (input == 3) {
return 0;
}
else {
cout <<"That is an invalid key" << endl;
}
}
}
When I run the program I am able to input the class node, then when I go to enter the student node, after hitting enter the program crashes. I know that there is a lot to look through, but I can't understand why it is. If someone would be able to tell me what I am doing wrong here I would greatly appreciate it. Thank you.

The addNodeToClass function never sets node->studentpointer. So when you follow that pointer in addNodeToStudent, you are dereferencing garbage.

Your code would be safer with a default node constructor:
typedef struct node {
node()
{
student_number = 0;
class_number = 0;
classpointer = nullptr;
studentpointer = nullptr;
}
int student_number;
int class_number;
struct node* classpointer;
struct node* studentpointer;
}* nodePtr;
And this would fix your issue because those attributes are not always initialized in your code (new node does not initialize the node attributes if there is no such constructor).

Related

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;

Creating Linked list insertion function but the code is not running

Unable to recognize the error in creating a linked list insertion function in linked list class the compiler giving this " error: qualified-id in declaration before '(' token But it seems like all the parenthesis are placed correctly.
#include <iostream>
using namespace std;
void additem();
void deleteitem();
void searchitem(int x);
struct student{
int data;
int * next;
};
student * head;
student * curr;
int main()
{
int x;
cout << "To add item type 1" << endl;
cin >> x;
switch(x)
{
case 1:
additem();
}
return 0;
}
void additem()
{
student * temp;
if(head == NULL)
{
temp = new student;
head = temp;
curr = temp;
temp->next = NULL;
cout << "Enter data" << endl;
cin >> temp->data << endl;
}
else if(head != NULL)
{
temp = new student;
curr->next = temp;
curr = temp;
temp->next = NULL;
cout << "Enter data" << endl;
cin >> temp->data ;
}
else{
break;
}
}
You're declaring a class and methods within main. This is not allowed (nested functions). linkedlist::additem needs to be defined before main.

Better way to code linked list?

I wrote this Linked List code and I am not able to create a single linked list since the value pointed by memory location of nodeValue in main function keep changing which in turn changes the head and tail value. I solved this by creating a Node object array((like nodeValue[5]) and passing the value, but this limits to 5 values. Is there a way to efficient way to code this without using a array of objects?
#include<iostream>
#include<string>
using namespace std;
class Node
{
public:
int value;
Node *nextNodePointer;
};
class linkedList
{
private:
int count = 0;
public:
Node *Head;
Node *Tail;
void AddNodeAfter(Node *);
//void removeNodeAfter(Node *);
void displayValues();
};
void linkedList::AddNodeAfter(Node *temp)
{
if (this->count == 0)
{
Head = temp;
Tail = temp;
count++;
}
else
{
Tail->nextNodePointer = temp;
Tail = temp;
count++;
}
}
Node createNodeObjects()
{
cout<< endl << "Enter integer value :";
Node temp;
cin >> temp.value;
temp.nextNodePointer = NULL;
return temp;
}
void linkedList::displayValues()
{
if (count == 0)
{
cout << endl << "Nothing to display";
}
else
{
Node value;
value = *Head;
for (int i = 1; i <= count; i++)
{
cout << endl << "Value: " << value.value;
value = *value.nextNodePointer;
}
}
}
int main()
{
cout << "Creating basic linked list" << endl;
linkedList LinkedList;
Node nodeValue;
while (1)
{
cout << endl << "Do you want to add a value to Node ?<Y/N> : ";
char choice;
cin >> choice;
if (choice == 'Y')
{
nodeValue = createNodeObjects();
LinkedList.AddNodeAfter(&nodeValue);
}
else
if (choice == 'N')
{
LinkedList.displayValues();
break;
}
else
cout << "Wrong choice" << endl;
}
}
In C++ , you can use list library ...
http://www.cplusplus.com/reference/list/list/

Print Function Linked Lists C++

I'm currently learning Linked Lists in C++, and I can't write a print function which prints out the elements of the list; I mean I wrote the function but it doesn't work properly.
#include <iostream>
using namespace std;
struct node
{
char name[20];
node* next;
};
node* addNewPerson(node* head)
{
node* person = new node;
cout << "Name: ";
cin >> person->name;
person->next = NULL;
if (head == NULL) //is empty
{
head = person;
}
else
{
person = person->next;
}
return head;
}
void printList(node* head)
{
node* temp = head;
cout << temp->name << endl;
}
int main()
{
node* head = NULL;
node* temp = head;
unsigned short people = 0;
cout << "How many people do you want to invite to the party?" << endl;
cout << "Answer: ";
cin >> people;
cout << endl;
for (unsigned short i = 1; i <= people; i++)
{
addNewPerson(head);
cout << endl;
}
cout << "LIST: " << endl;
cout << endl;
while (temp != NULL)
{
printList(temp);
temp = temp->next;
}
cin.get();
}
I am wondering what I'm doing wrong, please help me!
It is obvious that function addNewPerson is wrong.
node* addNewPerson(node* head)
{
node* person = new node;
cout << "Name: ";
cin >> person->name;
person->next = NULL;
if (head == NULL) //is empty
{
head = person;
}
else
{
person = person->next;
}
return head;
}
You allocated new node person.
node* person = new node;
Set its field next to NULL
person->next = NULL;
Then if head is not equal to NULL you set person to person->next
person = person->next;
As person->next was set to NULL it means that now also person will be equal to NULL.
Moreover the function returns head that can be changed in the function. However you ignore returned value in main
addNewPerson(head);
At least there should be
head = addNewPerson(head);
The valid function addNewPerson could look the following way
node* addNewPerson(node* head)
{
node* person = new node;
cout << "Name: ";
cin >> person->name;
person->next = head;
head = person;
return head;
}
And in main you have to write
for (unsigned short i = 1; i <= people; i++)
{
head = addNewPerson(head);
cout << endl;
}
Function printList does not output the whole list. It outputs only data member name of the first node that is of head.
void printList(node* head)
{
node* temp = head;
cout << temp->name << endl;
}
It should look the following way
void printList(node* head)
{
for ( ; head; head = head->next )
{
cout << head->name << endl;
}
}
And at last main should look as
int main()
{
node* head = NULL;
unsigned short people = 0;
cout << "How many people do you want to invite to the party?" << endl;
cout << "Answer: ";
cin >> people;
cout << endl;
for ( unsigned short i = 0; i < people; i++ )
{
head = addNewPerson(head);
cout << endl;
}
cout << "LIST: " << endl;
cout << endl;
printList( head );
cin.get();
}
In your addNewPerson function person->next never gets set, because head is always NULL.
addNewPerson method
Your addNewPerson method never added a new person to the list it just set the head to the new person.
node* addNewPerson(node* head)
{
node* person = new node;
cout << "Name: ";
cin >> person->name;
person->next = NULL;
if (head->next == NULL) //is empty
{
head->next = person;
}
else
{
person->next = head->next;
head->next = person;
}
return head;
}
printList method
Your method printList should do what it says and print the list, instead of just printing one person at a time.
void printList(node* head)
{
node* tmp = head;
while(tmp->next != NULL) {
tmp = tmp->next;
cout >> tmp->name >> endl;
}
}
main method
Upadted your main method with the new printList method.
int main()
{
node* head = new node;
unsigned short people = 0;
cout << "How many people do you want to invite to the party?" << endl;
cout << "Answer: ";
cin >> people;
cout << endl;
for (unsigned short i = 1; i <= people; i++)
{
addNewPerson(head);
cout << endl;
}
cout << "LIST: " << endl;
cout << endl;
cout << printList(head);
cin.get();
}
Also why are you using unsigned short and char arrays? Do you have a limited amount of memory? Why not just use int and string?
When you are adding a new person, it is not actually put into the linked list, since you have never invoked something like head -> next = person.
The section in your addNewPerson routine should be something like
if (head == NULL) {
head = person;
} else {
node * end = head;
while (end -> next != NULL) // find the end of the list to insert new person
end = end -> next;
end -> next = person;
}
And in the beginning you can't just pass head into addNewPerson, since it is a pointer with null value, the addNewPerson method accepts a pointer by value (value of the memory address it is pointing at) rather than a reference to head. So you need to use
node* addNewPerson(node* &head) { ... }
instead. Finally, when you declare temp, it first receives the value of head as well, so later access to temp would only give you NULL again. You need to change it to
node* &temp = head;
I think the problem is in how the link list is being added to in addNewPerson.
The input to addNewPerson is 'head' so each time, before adding a new node to the linked list, we need to traverse all the way down the linked list till the last node before appending 'person' to the linked list.
struct node
{
char name[20];
node* next;
};
node* addNewPerson(node* head)
{
node* person = new node;
//cout << "Name: ";
cin >> person->name;
person->next = head;
head = person;
return head;
}
void PrintLL(node *head)
{
while (head!=NULL){
cout<< head->name <<endl;
head=head->next;
}
}
int main() {
node* head = NULL;
node* temp = head;
int num_ppl;
cout << "How many people do you want to invite to the party?" << endl;
cout << "Answer: ";
cin >> num_ppl;
for(int arr_i = 0; arr_i < num_ppl; arr_i++){
head = addNewPerson(head);
}
PrintLL(head);
return 0;
}

linked list union

In my "void union" function I am unsure how to insert the data from both linked lists "A" and "B" that the user has input respectively since the "AUB" is not within the void function. I would have put:
AUB.insert
but I was unsure. Any suggestions?
#include "stdafx.h"
#include <iostream>
using namespace std;
class Sets
{
private:struct NODE
{
int info;
NODE *next;
};
NODE *list;
public:Sets()
{
list=NULL;
}
void Insert(int x)
{
NODE *p=list, *q=list, *r;
//create a new node
r = new (NODE);
r->info = x;
r->next = NULL;
//find the insertion place
while(p != NULL && p->info < x)
{
q=p;
p=p->next;
}
if(p==list)//x is the first info
{
list=r;
r->next=p;
}
else if(p==NULL)//x is the last info
{
q->next=r;
}
else //x is neither forst nor last info
{
r->next=p;
q->next=r;
}
}
void display()
{
NODE *p=list;
while(p != NULL)
{
cout << p->info << "-->";
p=p->next;
}
cout << "NULL\n";
}
void Union(Sets setA,Sets setB)
{
NODE *p=setA.list, *q=setB.list;
while(p != NULL && q != NULL)
{
if(p->info > q-> info)
{
(q->info)
q=q->next;
}
else if(p->info == q->info)
{
insert(p->info)
p=p->next;
q=q->next;
}
else//P->info < q->info
{
insert(p->info);
p=p->next;
}
}
while(p !=NULL)
{
insert(p->info);
p=p->next;
}
while(q != NULL)
{
insert(q->info);
q=q->next;
}
}
};
int main()
{
//create a set of integers
int x;
Sets A, B, setAUB;
cout << "Enter data for setA:\n";
cout << "Enter a group of positive integer numbers with -1 at the end end: ";
cin >> x;
while(x != -1)
{
A.Insert(x);
cin >> x;
};
//display setA
cout << endl << "setA=";
A.display();
cout << "Enter data for setB:\n";
cout << "Enter a group of positive integer numbers with -1 at the end end: ";
cin >> x;
while(x != -1)
{
B.Insert(x);
cin >> x;
};
//display setB
cout << endl << "setB=";
B.display();
setAUB.Union(A, B);
//display setAUB
cout << endl << "setAUB=";
setAUB.display();
system ("pause");
//terminate program
return 0;
};
You define it: void Union(Sets setA,Sets setB).
What are you doing? Both passed by value, and the return value is void - where does the result go?
Does your current object (this in the Union function) become that union? If so, what happens to the data already in it? You're not deleting it, so you're basically merging three sets, not two...
I would suggest to create a static merge function that would take the two parameters and return a new list which would be the merge of the two.
Otherwise, create a regular merge function, that would only take 1 parameter, and merge it into the current object.
By the way - why Sets, when it is obviously a sorted linked list?