cin a pointer reference to a struct - c++

I am using cin and cout in my program. I starts off fine because it is not executing any of the functions, but after you type your name, it throws an exception in the iostream library. wondering if it is a problem with using cin through refrence.`
// linkedlists.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
struct person {
string name;
int age;
struct person* next;
};
person *head = NULL;
int length() {
int count = 0;
person *current = head;
while (current->next != NULL) {
current = current->next;
count++;
}
return count;
}
void printlist() {
person *current = head;
while (current->next != NULL){
cout << "Name: " << current->name << " Age: " << current->age << "\n";
current = current->next;
}
}
void insert() {
// int choice;
person *newNode = (struct person*)malloc(sizeof(person));
//cout << "Press 1 to insert at beginning of list.\n";
//cin >> choice;
// switch (choice) {
//case 1:
newNode->next = head;
head = newNode;
cout << "What is this person's name?\n";
cin >> newNode->name;
cout << "\nWhat is the age of " << newNode->name << "?";
cin >> newNode->age;
cout << "The current list of people is " << length() << " long.\n";
printlist();
}
void menu() {
int choice;
cout << "Welcome to the person recorder! ";
bool inloop = true;
while (inloop) {
cout << "Press 1 to add more entries. Press 2 to print the entire list. Press 3 to exit the program.\n";
cin >> choice;
switch (choice) {
case 1:
insert();
case 2:
printlist();
case 3:
inloop = false;
}
}
}
/*void change(person* human) {
string temp_name;
int temp_age;
cout << "What is this person's name?\n";
cin >> temp_name;
cout << "\nWhat is this person's age?\n";
cin >> temp_age;
human->name = temp_name;
human->age = temp_age;
}
*/
int main()
{
menu();
}
using visual studio 2015, am a noob to c/c++ and trying to make a linked list.

The problem is caused by your allocation of person:
person *newNode = (struct person*)malloc(sizeof(person));
This will allocate memory on the heap for an instance of person, but it will not call the constructor of person and any of it's members. This does not matter for age and next since they are primitive types, but name is an std::string, which has a constructor that needs to be called for it to function properly.
In C++ you create instances of objects using the keyword new.
person *newNode = new person;
This will create a new instance of person, and also call its constructor, which will initialize name properly.
Once you are done with the instance of person, you will have use the keyword delete to clean it up.
delete newNode;
Similar to the difference between malloc and new, delete will free the memory, but also call the destructor, which is used by name to clean up any resources it may have allocated to store the string.

Related

Queue linked list not printing it's contents

I am trying to get input of a queue with the linked list implementation. The issue is that the contents of the queue aren't being printed. I tried debugging but it says that in the function displayCar that pointer p is null regardless. I can't tell what's wrong with why pointer p is NULL. Is there a missing reference when I am trying to push from the carInput function?
#include <iostream>
#include <queue>
using namespace std;
class record
{
public:
string ownerID, plateNumber;
record* next;
};
void push(string ownerID1, string plateNumber1, record **head, record **tail) {
record *n = new record();
n->ownerID = ownerID1;
n->plateNumber = plateNumber1;
n->next = NULL;
if (*head == NULL) {
*head =*tail= n;
}
else {
(*tail)->next = n;
*tail = n;
}
}
void pop(record** head, record** tail) {
record* p = *head;
while (*head != NULL) {
*head = (*head)->next;
free(p);
p = *head;
}
if (*head == NULL)
{
*tail = NULL;
}
}
void carInput(record *head, record *tail) {
char choice = 'Y';
string ownTemp, plateTemp;
while (choice == 'Y') {
cout << "Enter Owner Name: ";
cin >> ownTemp;
cout << "Enter Plate Number: ";
cin >> plateTemp;
push(ownTemp,plateTemp,&head,&tail);
cout << "Press [Y] for next input: ";
cin >> choice;
}
}
void displayCar(record* head, record *tail) {
record* p = head;
cout << "List Of Cars: \n";
int i = 1;
while (p!= NULL) {
cout << i << ". Owner Name: " << p->ownerID << endl;
cout << i << ". Plate Number: " << p->plateNumber<< endl;
pop(&head,&tail);
i++;
}
}
void serviceCar(record *head,record*tail) {
record* p = head;
string plateTemp;
int i = 0, time = 0;
char choice = 'Y';
cout << "Enter Plate Number:";
cin >> plateTemp;
while (p!= NULL) {
if (p->plateNumber == plateTemp) {
cout << "There is [" << i << "] car in queue before your turn. Estimated time in queue: " << time;
}
else {
i++;
time = time + 45;
}
pop(&head,&tail);
}
}
int main() {
record* head = NULL;
record*tail = NULL;
cout << ":: Car Record::\n\n";
carInput(head,tail);
displayCar(head,tail);
serviceCar(head, tail);
}
I don't know why you are punishing yourself with code like this when you are in C++ and there are plenty easier ways to do the same, but I'll try to help anyway by underlining the main problems:
1). The main reason that you must be struggling is that in the first push, even after *head =*tail= n;, the *head->next is still NULL and later when you'll try to iterate from the head, as you do in pop, *head = (*head)->next; you will get nothing.
2). if you want to do pop, you should delete one element for each call, not the whole collection - so you need if instead of while.
You have while where you using pop for each iteration and in the pop you also have the while, so think about it.
Also, you should be returning the value to display it easily - or change the way you trying to cout p in displayCar.
3). When you want to display the collection you just have to iterate through the collection instead of deleting all the elements, which will leave you empty collection after one display. You just need to iterate and display them, not to delete, something like that:
record* p = *head;
int i = 0;
while (p != NULL) {
cout << i << ". Owner Name: " << p->ownerID << endl;
cout << i << ". Plate Number: " << p->plateNumber<< endl;
p = p->next;
i++;
}
There are some other points that should be mentioned, but I think that's enough to get the code right direction - anyway, my advice would be to try to take a good look for simple linked-list how it's done and then try Queue linked-list, or just check already written examples and then try it by yourself. GeeksForGeeks
Your carInput receives pointers by value, and modifying those pointers has no effect on the pointers you pass to it.
Thus, main's head and tail are always null.
(You solved this with the pushing and popping functions, but failed to apply the same principle here.)
void carInput(record **head, record **tail) {
char choice = 'Y';
string owner, plate;
while (choice == 'Y') {
cout << "Enter Owner Name: ";
cin >> owner;
cout << "Enter Plate Number: ";
cin >> plate;
push(owner, plate, head, tail);
cout << "Press [Y] for next input: ";
cin >> choice;
}
}
You need to combine this fix with the fixes pointed out in the comments.

"exited, segmentation fault" with struct

For my C++ code below, I have declared a pointer of the "node" struct called "newNode" (node *newNode) and am trying to enter an id # and input it into newNode->id. After I enter in an id #, I get an error saying "exited, segmentation fault". I understand that this means we are trying to access a location in memory that we do not have access to, but am not aware how to fix this problem. I appreciate any feedback. Thank you.
#include <iostream>
using namespace std;
struct node
{
int id;
string name;
int age;
node *nxt;
};
node *head = NULL;
void InsertNode()
{
node *currentNode, *newNode, *nextNode;
cout << "You will now be prompted to enter the ID number, name, and age of a particular person..." << endl;
cout << "Enter ID number: ";
cin >> newNode->id;
cout << "Enter name: ";
cin >> newNode->name;
cout << "Enter age: ";
cin >> newNode->age;
currentNode = head;
while (currentNode != NULL)
{
if (newNode->id == currentNode->id)
{
cout << "The ID you entered was already assigned to another node. Please enter a different ID number for the node that you are inserting: " << endl;
cin >> newNode->id;
}else{
currentNode = currentNode->nxt;
}
}
if (head == NULL)
{
head = newNode;
}else{
currentNode = head;
while (currentNode != NULL)
{
nextNode = currentNode->nxt;
if (newNode->id < nextNode->id)
{
if(currentNode == head)
{
head = newNode;
newNode->nxt = nextNode;
}else if (nextNode->nxt == NULL && newNode->id > nextNode->id)
{
newNode->nxt = NULL;
nextNode->nxt = newNode;
}else{
newNode->nxt = nextNode;
}
}else{
currentNode = nextNode;
}
}
}
}
int main()
{
InsertNode();
return 0;
}
You have only created pointers that can point to a node of struct type but you haven't actually allocated memeory for these structures ..That is why you are getting segmentation fault as you are trying access a location that is not there .
First create a struct node via dynamic memory allocation say malloc and then try to assign I'd to it.
You have created a pointer to a struct, and when you're trying to insert something in the place of the pointer, but the pointer doesn't point to an object of the struct.
You need to dynamically allocate the node for insertion.
node *currentNode, *newNode, *nextNode;
newNode = new node(); // <- this is what you need to do, so you can insert.
cout << "You will now be prompted to enter the ID number, name, and age of a particular person..." << endl;
cout << "Enter ID number: ";
cin >> newNode->id;
cout << "Enter name: ";
cin >> newNode->name;
cout << "Enter age: ";
cin >> newNode->age;
Go forth and prosper.

While traversing the link list to read data my function prints up to penultimate node only, Suggest a way to print the whole list

I made a linked list in C++. For in which I have a function named: ListTraverse(). Which accepts a Node type pointer variable, where Node is my class. Please suggest me a method where it prints up to the last node.
Here is function call:
ListTraverse(&head);
And here is the function definition:
void ListTraverse(Node* node)
{
//Prints upto penultimate node
while (node->next != NULL)
{
cout << "\nNode details:\t"
<< node->read_data();
node=node->next;
}
}
And here you have the entire code.
#include <bits/stdc++.h>
#include <stdlib.h>
#include<typeinfo>
using namespace std;
class Node
{
private:
int data;
public:
Node *next;
void push_data(int x)
{
data = x;
}
int read_data()
{
return data;
}
};
void ListTraverse(Node *);
int main()
{
system("CLS");
//Creating Node type variables
Node head, second, tail;
int num, choice;
//Getting user input
cout << "Enter a number for head:\t";
cin >> num;
head.push_data(num);
cout << "Enter a number for second:\t";
cin >> num;
second.push_data(num);
cout << "Enter a number for tail:\t";
cin >> num;
tail.push_data(num);
//Assigning pointers to link up
head.next = &second;
second.next = &tail;
tail.next = NULL;
cout << "If you want to read data press 1:\t";
cin >> choice;
switch (choice)
{
case 1:
ListTraverse(&head);
break;
default:
cout << "Invalid choice";
break;
}
return 0;
}
//Funtion to print Data
void ListTraverse(Node* node)
{
//Prints upto penultimate node
while (node->next != NULL)
{
cout << "\nNode details:\t"
<< node->read_data();
node=node->next;
}
}
You should re-phrase your question. It seems that
my function prints up to penultimate node only
is the problem.
you wanted to print the whole list, not penultimate. And the fix is
void ListTraverse(Node* node)
{
//Prints upto the last node
while (node)
{
cout << "\nNode details:\t"
<< node->read_data();
node=node->next;
}
}

Issue with functions in singly linked list

UPDATED....New issue with addstudent function.
I made some changes based on feedback. I also made an update to the addstudent()function based on the assignment requirements and I am running into a strange issue.
The requirements for the addstudent function are that the parameters be a string id, string name, and string major. I added a line that allocates a new student node in this function, but it seems that only the ID is being kept. When I print the student information, the ID shows up, but the name and major are both blank. Where am I going wrong?
#include <iostream>
#include <string.h>
using namespace std;
class Student
{
public:
string ID;
string name;
string major;
public:
Student *next;
Student()
{
ID = "0";
name = "0";
major = "0";
next = NULL;
}
Student(string id, string name, string major)
{
ID = id;
name = name;
major = major;
next = NULL;
}
};
class Classroom
{
public:
Student* head;
Classroom()
{
head = NULL;
}
Classroom(Student* n)
{
head = n;
}
void addStudent(string id, string name, string major)
{
Student *n=new Student(id, name, major);
Student* current;
if (head == NULL)
{
n->next = head;
head = n;
}
else if(head->name > n->name)
{
n->next = head;
head = n;
}
else
{
current = head;
while (current->next!=NULL &&
current->next->name < n->name)
{
current = current->next;
}
n->next = current->next;
current->next = n;
}
}
void removeStudent(string id)
{
if (!head)
{
cout << "No students exist in this list.\n";
return;
}
Student **precurrent = &head,
*current = head;
while (current)
{
if (current->ID == id)
{
*precurrent = current->next;
cout<< "Student removed from list.\n";
return;
}
precurrent = &current->next;
current = current->next;
}
cout << "No student exists with this ID.\n";
}
void print()
{
if (!head) {
cout << "No students in list.\n";
return;
}
for (Student *temp = head; temp; temp = temp->next)
cout <<"\nStudent Information:\n Student ID: " << temp->ID
<< "\n Student Name: " << temp->name
<< "\n Student Major: " << temp->major << '\n';
}
void print(string id)
{
if (!head)
{
cout << "No students in list.\n";
return;
}
for (Student *temp = head; temp; temp = temp->next)
{
if (temp->ID == id)
{
cout <<"Student Information: \n"<< "Student ID: " << temp->ID <<'\n' << "Student Name: " << temp->name <<'\n' << "Student Major: " << temp->major << '\n';
return;
}
if(temp==NULL)
{
cout<<"Student ID does not exist.\n";
return;
}
}
}
bool isEmpty()
{
if (head == NULL)
return true;
else;
return false;
}
int getSize()
{
int count = 0;
if(head==NULL)
{
return count;
}
Student* temp = head;
while (temp != NULL)
{
temp = temp->next;
count++;
}
return count;
}
Student *at(int index)
{
Student *temp = head;
for (int i=1; i < index && temp; i++, temp = temp->next) {}
if (!temp)
cout << "Index not found.\n";
return temp;
}
};
int main()
{
Classroom cs;
int choice;
do
{
cout <<"\nPlease select an option below: (Enter 0 to exit)\n"
<< "1. Add student.\n"
<< "2. Remove student.\n"
<< "3. Print all student.\n"
<< "4. Print specific student.\n"
<< "5. Print student at index.\n"
<< "6. Print number of students.\n"
<< "7. Check if student list is empty.\n\n";
cin >> choice;
Student* s1 = new Student();
switch (choice)
{
case 0:
break;
case 1:
{
string id, name, major;
cout << "Enter Student ID:";
cin.ignore();
getline(cin, id);
cout << "Enter Student Name:";
getline(cin, name);
cout << "Enter Student Major:";
getline(cin, major);
cs.addStudent(id, name, major);
break;
}
case 2:
{
string id;
cout << "Enter Student ID of the Student to be removed: ";
cin >> id;
cs.removeStudent(id);
break;
}
case 3:
cs.print();
break;
case 4:
{
string id;
cout << "Enter ID of student to print: ";
cin >> id;
cs.print(id);
break;
}
case 5:
{
int index;
if(cs.isEmpty())
{
cout<< "No Students Exists.\n";
break;
}
cout << "Enter index to print: ";
cin >> index;
Student *s=cs.at(index);
if(s)
cs.print(s->ID);
break;
}
case 6:
cout << "There are "<< cs.getSize() << " students.\n";
break;
case 7:
if(cs.isEmpty())
cout<< "No Students Exists.\n";
else
cout << "The list is not empty.\n";
break;
default:
cout << "Enter valid option (0-7)\n";
}
} while (choice != 0);
return 0;
}
You have a large number of small errors that result in trouble throughout your code. With at() you are simply making it much harder than it needs to be. When you think about your at() function, there are simply two-conditions which must be true as you iterate over your list:
Your iteration counter must be less than the index, e.g. i < index (in C/C++ indexes are zero based on everything -- keep your code consistent) and
When you advance your list pointer, temp = temp->next, temp must not be NULL (or just temp for short).
You can put those together as:
Student *at(int index)
{
Student *temp = head;
int i = 0; /* C/C++ use zero based indexes */
for (; i < index && temp; i++, temp = temp->next) {}
if (!temp)
std::cerr << "error: index not found.\n";
return temp;
}
(where you have 2 loop-variables, temp and i and you use the comma operator to increment both in the for loop)
Similarly, you make your void removeStudent(std::string id) function much more complicated than it needs to be. When working with a list, you never keep track of a previous pointer, instead you use a pointer-to-pointer to hold the address of the current node (say Student **ppcurrent;) and you use a temporary pointer to point to the current node (say Student *pcurrent;).
When pcurrent->ID == id to remove, you simply set the pointer at the current address (as held by ppcurrent) to the next pointer in the list overwriting the Student to be removed with the ->next in the list. The beauty of this method is there are no special cases for head or any other node in the list, you simply replace the node at the current address with the next, e.g.
void removeStudent(std::string id)
{
if (!head) {
std::cout << "No students exist in this list.\n";
return;
}
Student **ppcurrent = &head,
*pcurrent = head;
while (pcurrent)
{
if (pcurrent->ID == id) {
*ppcurrent = pcurrent->next;
return;
}
ppcurrent = &pcurrent->next;
pcurrent = pcurrent->next;
}
std::cout << "No student exists with this ID.\n";
}
(See Linus on Understanding Pointers and see Why is “using namespace std;” considered bad practice?)
Your handling of std::cin and your use of std::cin.ignore() will miss cases where extraneous characters exist in stdin. You need to VALIDATE every use of std::cin to check for a stream error and then std::cin.clear() any stream error caused by a type mismatch or otherwise before you can use .ignore() and then you must empty all characters from stdin, not just one. Putting that together, you have a few issues to correct in main(), e.g.
do
{
std::cout <<"\nPlease select an option below: (Enter 0 to exit)\n"
" 1. Add student.\n"
" 2. Remove student.\n"
" 3. Print all student.\n"
" 4. Print specific student.\n"
" 5. Print student at index.\n"
" 6. Print number of students.\n"
" 7. Check if student list is empty.\n\n"
"choice: ";
if (!(std::cin >> choice)) {
std::cerr << "\nerror: invalid integer.\n";
std::cin.clear();
std::cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n');
continue;
}
std::cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n');
and then similarly with case: 5 of your switch() statement:
std::cout << "\nEnter index to print (zero based): ";
if (!(std::cin >> index)) {
std::cerr << "\nerror: invalid integer.\n";
std::cin.clear();
std::cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n');
continue;
}
There were probably a lot more than needed correcting, but the bulk of the remaining problems were just awkwardness in the way things were coded (which is to be expected given that you are just learning C++, so nothing against the way to approached it -- that is normal and to be expected). For example, above, you only need one std::cout to output your entire menu, and you don't add a std::endl; after outputting a string-literal, just include the '\n' at the end of the literal, example:
std::cout << "hello world\n";
instead of
std::cout << "hello world" << std::endl;
It's not that the use of std::endl; is wrong, it's simply that it is not needed. The same applies to your nesting of if { } else { } within your various functions where you can simply return if you if condition is met making the else superfluous and leading to unnecessary levels of code indention. For example print() can simply be:
void print()
{
if (!head) {
std::cout << "No students in list.\n";
return;
}
for (Student *temp = head; temp; temp = temp->next)
std::cout <<"\nStudent Information:\n Student ID: " << temp->ID
<< "\n Student Name: " << temp->name
<< "\n Student Major: " << temp->major << '\n';
}
We will leave it to you to make the remaining comparisons of the changes to your code. The only other note is try and limit your variables to the scope they are needed. You only allocate a new Student if the user selects add from the menu. Otherwise you are just needlessly allocating for all other menu choices. While you may have done this to avoid the error if you tried to declare and allocate within your case 1: statement, you simply need to enclose the entire case in a block, e.g. { .... } and you are free to declare anything you need within that code block, e.g.
case 1: {
std::string id {}, name {}, major {};
std::cout << "\nEnter Student ID: ";
getline (std::cin, id);
std::cout << "Enter Student Name: ";
getline (std::cin, name);
std::cout << "Enter Student Major: ";
getline(std::cin, major);
Student *s1 = new Student(id, name, major);
cs.addStudent(s1);
break;
}
or
case 5: {
int index;
if (cs.isEmpty()) {
std::cout << "\nlist is empty.\n";
break;
}
std::cout << "\nEnter index to print (zero based): ";
if (!(std::cin >> index)) {
std::cerr << "\nerror: invalid integer.\n";
std::cin.clear();
std::cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n');
continue;
}
Student *s = cs.at(index);
if (s)
cs.print (s->ID);
break;
}
(note: from my comment below your question, this is where you must validate the return from at() before calling print())
If you put all the pieces together, you would have:
#include <iostream>
#include <string>
#include <limits>
class Student
{
public:
std::string ID {}, name {}, major {};
Student *next;
Student()
{
ID = "0";
name = "0";
major = "0";
next = NULL;
}
Student(std::string ids, std::string names, std::string majors)
{
ID = ids;
name = names;
major = majors;
next = NULL;
}
};
class Classroom
{
public:
Student* head;
Classroom() { head = NULL; }
Classroom(Student* n) { head = n; }
void addStudent(Student *n)
{
Student* current;
if (head == NULL || head->name >= n->name) {
n->next = head;
head = n;
return;
}
current = head;
while (current->next && current->next->name < n->name)
current = current->next;
n->next = current->next;
current->next = n;
}
void removeStudent(std::string id)
{
if (!head) {
std::cout << "No students exist in this list.\n";
return;
}
Student **ppcurrent = &head,
*pcurrent = head;
while (pcurrent)
{
if (pcurrent->ID == id) {
*ppcurrent = pcurrent->next;
return;
}
ppcurrent = &pcurrent->next;
pcurrent = pcurrent->next;
}
std::cout << "No student exists with this ID.\n";
}
void print()
{
if (!head) {
std::cout << "No students in list.\n";
return;
}
for (Student *temp = head; temp; temp = temp->next)
std::cout <<"\nStudent Information:\n Student ID: " << temp->ID
<< "\n Student Name: " << temp->name
<< "\n Student Major: " << temp->major << '\n';
}
void print(std::string id)
{
if (!head) {
std::cout << "No students in list.\n";
return;
}
for (Student *temp = head; temp; temp = temp->next) {
if (temp->ID == id) {
std::cout <<"\nStudent Information:\n Student ID: " << temp->ID
<< "\n Student Name: " << temp->name
<< "\n Student Major: " << temp->major << '\n';
return;
}
}
std::cerr << "error: ID '" << id << "' not found.\n";
}
bool isEmpty()
{
if (head)
return false;
return true;
}
int getSize()
{
int count = 0;
Student* temp = head;
while (temp) {
temp = temp->next;
count++;
}
return count;
}
Student *at(int index)
{
Student *temp = head;
int i = 0; /* C/C++ use zero based indexes */
for (; i < index && temp; i++, temp = temp->next) {}
if (!temp)
std::cerr << "error: index not found.\n";
return temp;
}
};
int main()
{
Classroom cs;
int choice;
do
{
std::cout <<"\nPlease select an option below: (Enter 0 to exit)\n"
" 1. Add student.\n"
" 2. Remove student.\n"
" 3. Print all student.\n"
" 4. Print specific student.\n"
" 5. Print student at index.\n"
" 6. Print number of students.\n"
" 7. Check if student list is empty.\n\n"
"choice: ";
if (!(std::cin >> choice)) {
std::cerr << "\nerror: invalid integer.\n";
std::cin.clear();
std::cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n');
continue;
}
std::cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n');
switch (choice)
{
case 0:
break;
case 1: {
std::string id {}, name {}, major {};
std::cout << "\nEnter Student ID: ";
getline (std::cin, id);
std::cout << "Enter Student Name: ";
getline (std::cin, name);
std::cout << "Enter Student Major: ";
getline(std::cin, major);
Student *s1 = new Student(id, name, major);
cs.addStudent(s1);
break;
}
case 2: {
std::string id {};
std::cout << "\nEnter Student ID of the Student to be removed: ";
getline (std::cin, id);
cs.removeStudent(id);
break;
}
case 3:
cs.print();
break;
case 4: {
std::string id;
std::cout << "\nEnter ID of student to print: ";
getline (std::cin, id);
cs.print(id);
break;
}
case 5: {
int index;
if (cs.isEmpty()) {
std::cout << "\nlist is empty.\n";
break;
}
std::cout << "\nEnter index to print (zero based): ";
if (!(std::cin >> index)) {
std::cerr << "\nerror: invalid integer.\n";
std::cin.clear();
std::cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n');
continue;
}
Student *s = cs.at(index);
if (s)
cs.print (s->ID);
break;
}
case 6:
std::cout << "\nThere are "<< cs.getSize() << " students.\n";
break;
case 7:
if (cs.isEmpty())
std::cout<< "\nNo Students Exists.\n";
else
std::cout << "\nThe list is not empty.\n";
break;
default:
std::cout << "\nEnter valid option (0-7)\n";
}
} while (choice);
return 0;
}
Take time to understand the changes made and if you have further questions, just drop a comment below.
After going through your code, there are some flaws which need to be addressed.
void addStudent(Student *n)
{
Student* current;
if (head == NULL || head->name >= n->name)
{
n->next = head;
head = n;
}
else
{
current = head;
while (current->next!=NULL &&
current->next->name < n->name)
{
current = current->next;
}
n->next = current->next;
current->next = n;
}
In the above code,
Condition of string comparison need to be corrected. Using >= may not yield always the desired result as per alphabetical order is concerned. Reason being that it compares length or first element both. Instead "compare" function of string can be used.
The condition "if(head == NULL || head->name..." will jump into a situation of operating on a null pointer. So, use nested if statement instead of clubbing both condition under single if.
Coming to "at()" function:
Student* at(int index)
{
Student* temp = head;
int count=1;
if(head==NULL)
{
cout << "No students exist." << endl;
}
else
{
while(temp!=NULL)
{
if(count==index)
{
return(temp);
break;
}
else
{
count++;
temp = temp->next;
}
}
while(temp==NULL)
{
cout << "Index not found."<< endl;
break;
}
}
You need to de-reference the pointer in order to get the value (under switch condition, case 5) as you are returning a pointer.
Your function is not returning a value in all condition. You must finally return a pointer under each condition.
Also, instead of "while(temp == NULL)", you need to use "if(temp == NULL)"
Lastly use "nullptr" instead of "NULL" if you are working on C++11 or above version and use inbuilt containers like std::list if possible.

Inserting structs in sorted linked list and writing it to binary file

I have one serious problem. I need to write a program in which I input person details like first name, last name and age to a struct, which also contains pointer to the next person and than I need to write that to binary file. It must be ascending sorted by last name and than by first name, like linked list, using pointers, but only one pointer pointing to next struct. After entering all data it needs to go through file and find the struct with the lowest value and than using pointers print all data in ascending order.
This is the code I wrote but it's not working. I need help.
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cstring>
using namespace std;
struct person{
char firstName[20], lastName[20];
int age;
person *next;
};
void insert(char filename[], int n){
person *head = NULL;
ofstream people(filename, ios::binary | ios::trunc);
for(int i=0; i<n; i++){
system("cls");
person *per = new person;
cout << "firstName: ";
cin >> (*per).firstName;
cout << "lastName: ";
cin >> (*per).lastName;
cout << "age: ";
cin >> (*per).age;
if(head == NULL) {
(*per).next = head;
head = per;
}
else{
person *curr = head;
person *prev = NULL;
bool end = false ;
while(!end){
if(strcmp((*curr).lastName, (*per).lastName) ||
(!strcmp((*curr).lastName, (*per).lastName) &&
strcmp((*curr).firstName, (*per).firstName))){
end = true;
}
else {
prev = curr;
curr = (*curr).next;
}
}
if(curr==head){
(*per).next= head;
head = per;
}
else{
(*per).next = curr;
(*prev).next = per;
}
}
people.write((char *)&(*per), sizeof(*per));
}
people.close();
}
void print(char filename[]) {
person *head = NULL;
person *el;
person c,min;
ifstream people(filename, ios::binary);
people.read((char *)&c, sizeof(c));
min = c;
while(!people.eof()){
people.read((char *)&c, sizeof(c));
if(strcmp(c.lastName,min.lastName)== -1 ||
(!strcmp(c.lastName,min.lastName) &&
strcmp(c.firstName,min.firstName)==-1)){
min = c;
}
}
head = &min;
while (head != NULL) {
cout << (*head).firstName << " " <<(*head).lastName <<" "<<
(*head).age << endl;
el = head;
head = (*head).next;
delete el;
}people.close();
}
int main() {
int n, a;
char filename[40];
cout << "filename: " << endl;
cin.getline(filename, 40);
do{
do{ system("cls");
cout << "Choose one of the options: "<<endl;
cout << "1. insert "<<endl;
cout << "2. print "<<endl;
cout << "0. exit "<<endl;
cin >> a;
} while(a<1||a>2);
switch(a){
case 1: cout << "How many people would you like to enter? ";
cin >> n;
insert(filename, n);
break;
case 2:print(filename);
}
} while(a!=0);
return 0;
}
Looks like you are trying to create a sorted list but your condition for place to insert new node is wrong
strcmp((*curr).lastName, (*per).lastName) ||
(!strcmp((*curr).lastName, (*per).lastName) &&
strcmp((*curr).firstName, (*per).firstName)
It essentially tells - insert new person before curr as soon as it is different from curr.
You have to change it to be - insert new person as soon as it is bigger than (less than) curr - depending on the order of sorting.
So instead of checking strcmp != 0 check strcmp >0 or <0
Of course replacing c-strings with std::string will make it a lot easier and safer