program skips over getline [duplicate] - c++

This question already has answers here:
getline not asking for input? [duplicate]
(3 answers)
Closed 7 years ago.
When I run this program, and select option 1, it prints both cout statements in void CTree::Add() at once, jumping over the cin.getline(newPerson->name, 20);
I had the same piece of code in linked list program and it behaved properly, I am really stuck at how to fix this.
//header file
using namespace std;
struct PersonRec
{
char name[20];
int bribe;
PersonRec* leftLink;
PersonRec* rightLink;
};
class CTree
{
private:
PersonRec *tree;
bool IsEmpty();
void AddItem( PersonRec*&, PersonRec*);
void DisplayTree(PersonRec*);
public:
CTree();
//~CTree();
void Add();
void View();
};
//implementation file`
#include <iostream>
#include <string>
using namespace std;
#include "ctree.h"
CTree::CTree()
{
tree = NULL;
}
//PersonList::~MyTree()
//{
//
//}
bool CTree::IsEmpty()
{
if(tree == NULL)
{
return true;
}
else
{
return false;
}
}
void CTree::Add()
{
PersonRec* newPerson = new PersonRec();
cout << "Enter the person's name: ";
cin.getline(newPerson->name, 20);
cout << "Enter the person's contribution: ";
cin >> newPerson->bribe;
newPerson->leftLink = NULL;
newPerson->rightLink = NULL;
AddItem(tree, newPerson);
}
void CTree::View()
{
if (IsEmpty())
{
cout<<"The list is empy";
}
else
{
DisplayTree(tree);
}
};
void CTree::AddItem( PersonRec*& ptr, PersonRec* newPer )
{
if (tree == NULL)
{
ptr = newPer;
}
else if ( newPer->bribe < ptr->bribe)
AddItem(ptr->leftLink, newPer);
else
AddItem(ptr->rightLink, newPer);
}
void CTree::DisplayTree(PersonRec* ptr)
{
if (ptr == NULL)
return;
DisplayTree(ptr->rightLink);
cout<<ptr->name<<" "<<"$"<<ptr->bribe <<endl;
DisplayTree(ptr->leftLink);
}
//driver file
#include <iostream>
using namespace std;
#include <cstdlib>
#include "ctree.h"
int displayMenu (void);
void processChoice(int, CTree&);
int main (void)
{
int num;
CTree ct;
do
{
num = displayMenu();
if (num != 3)
processChoice(num, ct);
} while (num != 3);
return 0;
}
int displayMenu (void)
{
int choice;
cout << "\nMenu\n";
cout << "==============================\n\n";
cout << "1. Add student to waiting list\n";
cout << "2. View waiting list\n";
cout << "3. Exit program\n\n";
cout << "Please enter choice: ";
cin >> choice;
return choice;
}
void processChoice(int choice, CTree& myTree)
{
switch (choice)
{
case 1: myTree.Add (); break;
case 2: myTree.View (); break;
}
}

After you read choice in the displayMenu subroutine, you leave the remainder of the user's input line. Specifically, you leave the end-of-line indicator: '\n'. Later, when you read newperson->name, you are actually retrieving the remainder of the menu line, and not the name line.
You can use istream::ignore to consume the rest of menu choice line, before trying to read the name.
Replace the last two lines of displayMenu with these:
cin >> choice;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
return choice;

Adding a
cin.ignore(2000, '\n');
before the input call fixes the problem!

Related

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;
}
}

How do I create a template object based off of user input?

I have made an array based queue with a template so that the user can decide what kind of data is held inside the queue but I cannot figure out how gather input and then from that create a queue of that data type.
Here is my Queue
#include <memory>
using namespace std;
template<class itemType>
class Queue
{
private:
unique_ptr<itemType []> queueArray;
int queueSize;
int front;
int rear;
int numItems;
public:
Queue(int);
itemType peekFront();
void enqueue(itemType item);
void dequeue();
bool isEmpty() const;
bool isFull() const;
void clear();
};
And I have tried this and many other ways but cant figure out how to tell what type of data the user inputs and then create a Queue with that type of data.
int main()
{
const int MAXSIZE = 5;
int choice;
cout << "1. integer queue\n" << "2. string queue\n" << "3. float queue\n";
choice = menu();
if(choice == 1)
{
Queue<int> newQueue(MAXSIZE);
int data;
}
else if(choice == 2)
{
Queue<string> newQueue(MAXSIZE);
string data;
}
else if(choice == 3)
{
Queue<float> newQueue(MAXSIZE);
float data;
}
else
cout << "Number needs to be 1-3." << endl;
cout << "Enter an item to add" << endl;
cin >> data;
newQueue->enqueue(data);
Thanks everyone for the help! I almost have it done, but now that I have all virtual functions how do I call peekFront()? Since the virtual functions can't return itemType right?
You need runtime polymorphism to solve this problem. This can either be achieved with a base class:
class IQueue {
virtual ~IQueue() = default;
virtual void enqueue(istream&) = 0;
};
template<class itemType>
class Queue : public IQueue
{
//...
public:
void enqueue(istream& is) override {
itemType item;
is >> item;
enqueue(item);
}
//...
};
And use as a pointer
int main() {
//...
unique_ptr<IQueue> newQueue;
//...
if(choice == 1)
{
newQueue.reset(new Queue<int>(MAXSIZE));
int data;
}
//...
newQueue->enqueue(cin);
//...
}
Or something like std::variant.
Well, you are almost there.
You just need to not loose the scope of your data and newQueue variables.
template <typename T>
T input()
{
T data;
cout << "Enter an item to add" << endl;
cin >> data;
return data;
}
int main()
{
const int MAXSIZE = 5;
int choice;
cout << "1. integer queue\n" << "2. string queue\n" << "3. float queue\n";
choice = menu();
if(choice == 1)
{
Queue<int> newQueue(MAXSIZE);
newQueue->enqueue(input<int>());
}
else if(choice == 2)
{
Queue<string> newQueue(MAXSIZE);
newQueue->enqueue(input<string>());
}
else if(choice == 3)
{
Queue<float> newQueue(MAXSIZE);
newQueue->enqueue(input<float>());
}
else
cout << "Number needs to be 1-3." << endl;
}
You still have some problem with this architecture, for example, maybe you want to move your queues outside these ifs, otherwise you can't use them anymore. (Read about scope).
You could also look at std::variant for these kind of situations.

Reading data from file into queue in c++

I am having trouble figuring out how to get my input data into my queue... I am so close to getting this to work right.
I know I am just confused about how things are working. I have used example code and my instructions to come up with a working program that appears to be working correctly (other than not actually putting my input file data into the queue). I bypassed the function I was trying to make for this. In addition to this, I was trying to write a function to remove an employee from the queue (which I think does work), but I am not sure I was able to get it right...
I have not taken a programming class for over 10 years and really would love to get any help in understanding what I am doing and getting that darn data into the queue.
Below is my main driver file. I will provide my header file code if needed. Thanks in advance for any help you can provide on this.
//Program Assignment #3
//Creates Queue as a Linked Structure
#include<iostream>
#include<string>
#include<fstream>
#include"Employee.h"
#include"LinkedQ.h"
using namespace std;
struct Node
{
LinkedQ nodeQ;
Employee EmpNumber;
Employee LastName;
Employee FirstName;
Employee ServiceYears;
};
void loadFile(LinkedQ &);
void addEmp(LinkedQ &);
void delEmp(LinkedQ &);
int main()
{
LinkedQ empList;
int choice;
int numIn, yearsIn;
string LastName;
string FirstName;
LinkedQ empIn;
ifstream input;
input.open("Employee.txt");
while (input)
{
input >> numIn >> LastName >> FirstName >> yearsIn;
if (input)
{
cout << "this is where we load data from the file into the queue\n";
system("pause");
//empIn.Enqueue(numIn, LastName, FirstName, yearsIn);
//empList.addEmp(empIn);
}
}
input.close();
do
{
//display menu
system("cls");
cout << "\t\tMenu: \n"
<< "\t1. Add Employee\n"
<< "\t2. Remove Employee\n"
<< "\t3. Count of Employees\n"
<< "\t4. Quit\n\n";
cout << "Enter your choice and press return: ";
cin >> choice;
switch (choice)
{
case 1:
addEmp(empList); // call to function to add an employee to the queue
break;
case 2:
delEmp(empList); // call to fucntion to remove an employee from the queue
break;
case 3:
cout << endl << "Count of Employees: "
<< empList.GetLength() << endl; // See how many employees are in the queue
system("pause");
break;
case 4:
cout << "End of Program"; // End Program
break;
default:
cout << "Not a valid choice!" << endl;
cout << "Choose Again."; // Handling incorrect inputs
system("pause");
break;
}
} while (choice != 4); // If choice is not 4, continue running program
return 0;
}
//***********************************
//Loads the file (having trouble figuring out how to implement this part)
//***********************************
void loadFile(Employee &empList)
{
int numIn, yearsIn;
string LastName;
string FirstName;
LinkedQ empIn;
ifstream input;
input.open("Employee.txt");
while (input)
{
input >> numIn >> LastName >> FirstName >> yearsIn;
if (input)
{
cout << "this is where we load data from the file into the queue";
//empIn.setFields(numIn, LastName, FirstName, yearsIn);
//empList.addEmp(empIn);
}
}
input.close();
}
//***************************************
//add an employee
//***************************************
void addEmp(LinkedQ &empList)
{
Employee newEmp;
newEmp.user();
empList.Enqueue(newEmp);
}
//****************************************
//remove a employee
//****************************************
void delEmp(LinkedQ &empList)
{
Employee EmpToRemove;
int empNum;
// bool successful;
cout << "Please enter EMPLOYEE NUMBER of employee to remove:";
cin >> empNum;
EmpToRemove.setEmpNumber(empNum);
empList.Dequeue(EmpToRemove);
//successful = empList.Dequeue(EmpToRemove);
//if (successful == true)
//{
cout << "Removed" << endl << endl;
system("pause");
//}
//else
//{
// cout << "Emp Not found" << endl << endl;
//}
}
Here is the LinkedQ implementation file:
//LinkedQ class
#include "LinkedQ.h"
#include <cstddef>
#include <new>
struct NodeType
{
Employee info;
NodeType* next;
};
LinkedQ::LinkedQ(void)
{
newNode = nullptr;
front = NULL;
rear = NULL;
length = 0;
}
void LinkedQ::MakeEmpty()
{
NodeType* tempPtr;
while (front != NULL)
{
tempPtr = front;
front = front->next;
delete tempPtr;
}
rear = NULL;
}
LinkedQ::~LinkedQ(void)
{
MakeEmpty();
}
bool LinkedQ::IsFull() const
{
NodeType* location;
try
{
location = new NodeType;
delete location;
return false;
}
catch (std::bad_alloc exception)
{
return true;
}
}
bool LinkedQ::IsEmpty() const
{
return (front == NULL);
}
void LinkedQ::Enqueue(Employee newItem)
{
if (IsFull())
cout << "Queue is Full";
// throw FullQueue();
else
{
NodeType* newNode;
newNode = new NodeType;
newNode->info = newItem;
newNode->next = NULL;
if (rear == NULL)
{
front = newNode;
}
else
{
rear->next = newNode;
}
rear = newNode;
length++;
}
}
void LinkedQ::Dequeue(Employee& item)
{
if (IsEmpty())
{
//throw EmptyQueue();
cout << "Queue is empty";
}
else
{
NodeType* tempPtr;
tempPtr = front;
item = front->info;
front = front->next;
if (front == NULL)
{
rear = NULL;
}
delete tempPtr;
length--;
}
}
int LinkedQ::GetLength() const
{
return length;
}
And here is the Employee implementation file:
//employee Class
#include"Employee.h"
//Constructor
Employee::Employee()
{
EmpNum = 0;
}
//setters
void Employee::setEmpNumber(int eNum)
{
EmpNum = eNum;
}
void Employee::setEmpName(string LName)
{
LastName = LName;
}
void Employee::setEmpFirstName(string FName)
{
FirstName = FName;
}
void Employee::setYearsService(int years)
{
YearsService = years;
}
void Employee::setFields(int num, string LN, string FN, int years)
{
EmpNum = num;
LastName = LN;
FirstName = FN;
YearsService = years;
}
void Employee::user()
{
string inputString;
int intNumber;
cout << "Employee Number ";
cin >> intNumber;
while (intNumber <= 0)
{
cout << "Employee Number ";
cin >> intNumber;
}
EmpNum = intNumber;
cout << "Last Name: ";
cin >> inputString;
LastName = inputString;
cout << "First Name: ";
cin >> inputString;
FirstName = inputString;
cout << "Years of Service: ";
cin >> intNumber;
while (intNumber < 0)
{
cout << "Years of Service ";
cin >> intNumber;
}
cout << endl;
YearsService = intNumber;
}
//getters
const int Employee::getEmpNumber()
{
return EmpNum;
}
const string Employee::getLastName()
{
return LastName;
}
const string Employee::getFirstName()
{
return FirstName;
}
const int Employee::getYearsService()
{
return YearsService;
}
//overloads
bool Employee::operator == (const Employee &right)
{
bool status;
if ( EmpNum == right.EmpNum)
status = true;
else
status = false;
return status;
}
bool Employee::operator != (const Employee &right)
{
bool status;
if (EmpNum != right.EmpNum)
status = true;
else
status = false;
return status;
}
I think the parameter of loadFile should be of type LinkedQ, which, if I understand it correctly, is the queue class/struct, and the empIn variable should be of type Employee.
Edit:
The method you call on the empList object should be Enqueue, instead of addEmp.

C++ how to restart the loop if user just presses enter or if the input is invalid?

I'll start by saying I have worked on this for 3 days now and this is only my second semester programming. I know this question is probably easy for most, but I really have very little experience.
The code I have written all works as intended except the invalid/blank entry validation. Anything I have found and tried just breaks other parts of the code or doesn't work at all.
Here are the instructions given in the homework for the part I am having issues with:
"Any invalid input for the menu will simply redisplay the menu.
Option 1 will prompt for a userName. An empty name will be ignored."
Here is my code. Any help is greatly appreciated.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
vector<string> usernames;
void listMenu();
void addName();
void listNames();
void removeName();
int main()
{
char entry;
bool exit = false;
while (exit == false)
{
cout << "Choose from the following menu: \n";
listMenu();
cin >> entry;
if (entry == '\n')
{
listNames();
}
if (entry == '1')
{
addName();
}
else if (entry == '2')
{
listNames();
}
else if (entry == '3')
{
removeName();
}
else if (entry == 'x' || entry == 'X')
{
exit = true;
}
}
usernames.clear();
return 0;
}
void listMenu()
{
string menu[4] = { "1. Add a username","2. List all usernames","3. Delete a username","X. Exit" };
for (int i = 0; i < 4; i++) {
cout << menu[i] << endl;
}
}
void addName()
{
string name;
cout << "Enter a username: " << endl;
cin >> name;
usernames.push_back(name);
}
void listNames()
{
int n = 1;
cout << "**************\n";
for (auto& x : usernames)
{
cout << n <<". "<< x <<endl;
n++;
}
cout << "**************\n";
}
void removeName()
{
int x;
cout << "Which username would you like to remove?\n";
listNames;
cin >> x;
usernames.erase(usernames.begin()+x);
}
You can test your input and clear it if it's invalid. Using cin.fail, cin.clear and cin.ignore.
#include<iostream>
using namespace std;
bool cond;
int main() {
int n;
do {
cout << "Enter an integer number:";
cin >> n;
cond = cin.fail();
cin.clear();
cin.ignore(INT_MAX, '\n');
} while(cond);
return 0;
}

Linked Lists C++, output not showing in display function

#include <string>
using namespace std;
class PersonList
{
private:
char aName[7];
int aBribe;
PersonList *link;
public:
void addNodes();
void display();
};
#include <iostream>
#include <string>
using namespace std;
#include "mylink.h"
void PersonList::addNodes()
{
PersonList *temp2;
PersonList* startPtr = new PersonList();
PersonList* current = new PersonList();
PersonList *temp = new PersonList();//created the first node on the list
cout<<"Enter the person's name: ";
cin>>temp->aName;
cout<<"Enter the person's contribution: ";
cin>>temp->aBribe;
temp->link=NULL;//when i get last node, link will point to null(where am i in list?)
if(startPtr==NULL)
{
startPtr = temp;
current = startPtr;
}
else
{
temp2 = startPtr;
while(temp2->link!=NULL)
temp2 = temp2->link;
temp2->link=temp;
}
//}
}
void PersonList::display()
{
PersonList *temp;
PersonList *startPtr = this;
temp=startPtr;
while(temp != NULL)
{
cout<<temp->aName<<"\t\t"<<temp->aBribe<<endl;
temp = temp->link;
}
}
#include <iostream>
#include "mylink.h"
using namespace std;
int displayMenu (void);
void processChoice(int, PersonList&);
int main()
{
int num;
PersonList myList;
do
{
num = displayMenu();
if (num != 3)
processChoice(num, myList);
} while (num != 3);
return 0;
}
int displayMenu(void)
{
int choice;
cout << "\nMenu\n";
cout << "==============================\n\n";
cout << "1. Add student to waiting list\n";
cout << "2. View waiting list\n";
cout << "3. Exit program\n\n";
cout << "Please enter choice: ";
cin >> choice;
cin.ignore();
return choice;
}
void processChoice(int choice, PersonList& p)
{
switch(choice)
{
case 1: p.addNodes();
break;
case 2: p.display();
break;
}
}
My question is the display function is not displaying name and contribution that I enter.
Im using temp variable as a pointer node to call aName and aBribe. This goes through the list while it has not reached null. Nothing shows in output
You are creating a new list:
PersonList *startPtr = new PersonList();
and then showing that. So, naturally it is empty.
You have a similar problem in your addNodes method. You are adding nodes to a new list, then throwing it away, which is actually a memory leak.