C++ Validation - Truncation set as next input - c++

I consistently run into this problem where I'm trying to validate user input but I find myself using tons of ignores() throughout my program. Since it is a school program I'm only limited to just iostream, cctype, and student.h libraries. The problem is I need to make sure the user does not try to enter alpha characters into an integer field which I thought I covered with if(!(cin >> val)) and then I use cin.ignore(numeric_limits<streamsize>::max(), '\n'); to ignore anything extra (for instance if they try to enter a decimal into an integer field). Something is not working correctly though as I am either unable to input into name field or I get the remaining decimal as the name (if I enter 123.6, the name will be .6). Does someone know a better way to validate integers than using mass ignores?
Main
#include <iostream>
using namespace std;
#include "student.h"
//**************************************************************************
bool validInt(int&);
//**************************************************************************
int main()
{
Student student;
bool validInput;
cout << "You have Chosen to Add a New Student." << endl;
cout << "---------------------------------------" << endl;
// Student ID Validation
do
{
cout << "Enter Student ID (ex. 123): ";
validInput = validInt(student.id);
}while(!validInput);
cout << "Enter Student Name (ex. John Doe): ";
cin.getline(student.name, 50);
cout << "Enter Student City and State (ex. St. Louis, Missouri): ";
cin.getline(student.citystate, 50);
cout << "\n\nStudent ID: " << student.id << endl;
cout << "Student Name: " << student.name << endl;
cout << "Student City / State: " << student.citystate << endl;
return 0;
}
//**************************************************************************
bool validInt(int& val)
{
bool valid = true;
if(!(cin >> val))
{
cout << "\nERROR: Please enter a Positive Whole Number" << endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
valid = false;
}
return valid;
}
Student Header
#ifndef STUDENT_H
#define STUDENT_H
//**************************************************************************
struct Student
{
int id;
char name[50];
char citystate[50];
friend ostream& operator<<(ostream& out, const Student& data);
bool operator == (const Student &rhs) const;
bool operator != (const Student &rhs) const;
bool operator < (const Student &rhs) const;
bool operator > (const Student &rhs) const;
bool operator <= (const Student &rhs) const;
bool operator >= (const Student &rhs) const;
};
//**************************************************************************
ostream& operator << (ostream& out, const Student& data)
{
out << data.id << " " << data.name << endl;
return out;
}
//**************************************************************************
bool Student::operator == (const Student &rhs) const
{
return (this->id == rhs.id);
}
//**************************************************************************
bool Student::operator != (const Student &rhs) const
{
return (this->id != rhs.id);
}
//**************************************************************************
bool Student::operator < (const Student &rhs) const
{
return (this->id < rhs.id);
}
//**************************************************************************
bool Student::operator > (const Student &rhs) const
{
return (this->id > rhs.id);
}
//**************************************************************************
bool Student::operator <= (const Student &rhs) const
{
return (this->id <= rhs.id);
}
//**************************************************************************
bool Student::operator >= (const Student &rhs) const
{
return (this->id >= rhs.id);
}
#endif

Usually you would use std::getline(std::string&,std::istream&) for line orientated input and parse the number with an istringstream. However, since you aren't allowed to use neither std::string nor std::stringstream you need to parse the integer yourself.
But first the explanation for your errors.
Explanation
Something is not working correctly though as I am either unable to input into name field
When you enter a correct integer the newline token \n is not extracted from the string, that's why cin.getline(student.name, 50); won't extract anything: the next character in std::cin is \n, the line ends and the std::getline fills student.name with the extractet line, which is empty.
or I get the remaining decimal as the name (if I enter 123.6, the name will be .6).
Again, this is the same: you only extract the integer, but you don't extract the rest of the line.
Temporary solution
Ignore the rest of the line in your validInt:
bool validInt(int& val)
{
bool valid = true;
if(!(cin >> val))
{
cout << "\nERROR: Please enter a Positive Whole Number" << endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
valid = false;
}
cin.ignore(numeric_limits<streamsize>::max(), '\n');
return valid;
}
Correct solution
The correct solution is a little bit more elaborate, since you would have to write something that extracts single characters, checks whether they are digits (or a minus or plus), saves those as integer and ignores the rest of the line. Don't worry, this is possible with only <iostream>

Related

C++ friend operator overloading cin>>

I am replacing a Read in function with a friend operator. I am having trouble referencing the friend operator in a void function. I am receiving and error "No member named 'Read' in Date" in the void GetDates function. Does anyone know how to fix this? Thank you!
Question 2:
I am now using cout<< operator but I am receiving errors for my variables: "'mn' is a private member of 'Date'"
class Date {
private:
int mn; //month component of a date
int dy; //day component of a date
int yr; //year comonent of a date
public:
//constructors
Date() : mn(0), dy(0), yr(0)
{}
Date(int m, int d, int y) : mn(m), dy(d), yr(y)
{}
//input/output functions
friend istream& operator>>(istream& Read, Date& d); //overload friend Read
friend ostream& operator<<(istream& write, Date& d); //overload friend write
void GetDates();
void Sort();
};
//Date class member functions
istream& operator >>(istream& Read, Date& d) //**NEED TO REPLACE with overload vs as friends to Date function**
{
char skip_char;
Read >> d.mn >> skip_char >> d.dy >> skip_char >> d.yr;
return Read;
}
void GetDates(Date l[], int &n) //reads list l, and returns count in n
{
cout << "How many date values are to be processed (1 - 100)? ";
cin >> n;
while ((n < 0) || (n > 100)) {
cout << "Invalid value; enter number between 0 and 100: ";
cin >> n;
}
for (int i = 0; i < n; i++) {
cout << "Enter a date (mm/dd/yyyy): ";
l[i].Read(); //ERROR HERE
}
}
ostream& operator <<(ostream& write, Date& d) //friend write
{
if (d.mn < 10)
cout << '0';
cout << d.mn << '/';
if (d.dy < 10)
cout << '0';
cout << d.dy << '/';
if (d.yr < 1000)
cout << '0';
if (d.yr < 100)
cout << '0';
if (d.yr < 10)
cout << '0';
cout << d.yr;
return write;
}
Read is the name of the stream that you are extracting from. An example of a stream that you can read from is cin. You need to replace this line:
l[i].Read(); //ERROR HERE
with
cin >> l[i];
Inside operator>> the cin object is now called Read.
The issue with your operator<< is that it needs to be declared as a friend, the same way you've done with operator>>.
Also, you are writing to cout instead of writing to write. This will not work, as soon as you try to writing to any other stream.

How to make function "run" work. The program just exits when run is called

I'm trying to make a login system (in progress) for a challenge(self), but the function "run" that returns a function, exits when called. Kindly assist
#include <iostream>
#include <string>
#include <array>
#include <vector>
using namespace std;
//initialise function pointer that is void and takes no parameter
typedef void (*funcpointer)();
//forward declare a function run that takes an integer parameter
funcpointer run(int op);
//declare class user with username and password
class User {
private:
string m_name;
string m_password;
public:
//constructor for class
User()
{
}
//friend functions that need to access class members
friend istream& operator>>(istream& in, User& user);
friend ostream& operator<<(ostream& out, User& user);
friend void access();
friend void display();
};
//vector that stores class
std::vector<User> m_user;
//allows user defined input of class members
istream& operator>>(istream& in, User& user)
{
cout << "Enter your username: ";
in >> user.m_name;
cout << "Enter your password: ";
in >> user.m_password;
return in;
}
//ouputs Class member contents in user defined manner(allows cout << class)
ostream& operator<<(ostream& out, User& user)
{
out << "Username is: " << user.m_name << " Password is: " << user.m_password << '\n';
return out;
}
//allows user to choose whether to log in, make ne user or view users
void logIn()
{
int num;
cout << "Would you like to: \n1: Make new user\n2: Log In\n3: Display users\n";
do {
cin >> num;
} while ((num != 1) && (num != 2) && (num != 3));
run(num);
}
void newUser()
{
User x;
cin >> x;
m_user.push_back(x);
}
void access()
{
string name, password;
cout << "Enter username: ";
getline(cin, name);
for (size_t i = 0; i < m_user.size(); i++) {
if (name == m_user[i].m_name) {
cout << m_user[i].m_name << " found. Enter password: ";
getline(cin, password);
if (password == m_user[i].m_password) {
cout << "access granted";
}
else
cout << "Wrong password\n";
}
else
cout << "Username not found!\n";
}
}
void display()
{
int count = 1;
for (auto& users : m_user) {
cout << count << ": " << users.m_name << '\n';
}
}
//function run that returns function
funcpointer run(int op)
{
switch (op) {
default:
case 1:
return newUser;
case 2:
return access;
case 3:
return display;
}
}
int main()
{
logIn();
return 0;
}
i expected the function num to call newUser when 1 is passed, but exits instead with 0
what could be the problem? i also tried changing the parameter to char and string with the same result
If you return funcpointer you probably want to call it. You could make it by writing () after funcpointer object like this run(num)();

no viable conversion from 'int' to 'student' c++

(Edited version)
I am currently coding Binary Search Tree algorithm. (using xCode IDE)
I'm taking the data from txt file and insert it as binarysearchtree.
This is the sample of data from txt file.
3800 Lee, Victor; 2.8
3000 Brown, Joanne; 4.0
As you can see in student.h, there are 2 variables which are id and student. Id contains the data "3800" and student contains "Lee, Victor; 2.8". Each line of the txt consider as one root.
Now, I have to search by a unique key which is id(Ex. "3800") and print out if it is found in the tree.
I have 5 files, BinaryNode.h, BinaryTree.h, BinarySearchTree.h, Student.h, main.cpp.
All 3 of the binary header file are using template and Student.h has no template.
So, here is my int main.
int main()
{
BinarySearchTree<Student> tree;
getData(tree); (I didn't include getData part, but consider tree has txtfile data.)
bool found = false;
char input;
do
{
cout << "Enter a key letter to access to a corresponding menu." << endl << endl;
cout << "T – Print tree as an indented list" << endl;
cout << "S – Search by a unique key (student ID)" << endl;
cout << "B – Tree Breadth-First Traversal: Print by level" << endl;
cout << "D – Depth-First Traversals: inorder, preorder, postorder" << endl;
cout << "R – Find the longest branch and print it (from leaf to root)" << endl;
cout << "H – Help" << endl;
cout << "Q – Quit" << endl << endl;
cout << "Input: ";
cin >> input;
cout << endl;
if(input == 'T' || input == 'S' || input == 'B' || input == 'D' || input == 'R' || input == 'H' || input == 'Q' || input == 'A')
{
if(input == 'T')
{
//print tree as indented
}
else if(input == 'S')
{
//search by student ID
Student *result = new Student;
int id;
cout << "Enter the student ID to search the matching student." << endl;
cin >> id;
result->setId(id);
found = tree.getEntry(*result);
}
I cin the input data into result and tried to search for the data.
//My getEntry function in public function definition
template<class ItemType>
bool BinarySearchTree<ItemType>::getEntry(ItemType& anEntry)
{
BinaryNode<ItemType>* returnedItem = findNode(BinaryTree<ItemType>::rootPtr, anEntry);
if (returnedItem)
{
anEntry = returnedItem->getItem();
return true;
}
else return false;
}
//findNode function
template<class ItemType>
BinaryNode<ItemType>*
BinarySearchTree<ItemType>::findNode(BinaryNode<ItemType>* nodePtr,
ItemType & target)
{
ItemType result = result.getId(); <------- ******error here*******
ItemType root = nodePtr->getItem().getId();
if (nodePtr == nullptr)
return nullptr;
if (result == root)
return root;
if (result > root)
root = findNode(nodePtr->getRightPtr(), target);
else
root = findNode(nodePtr->getLeftPtr(), target);
return root;
}
I have an error on my findNode function.
->No viable conversion from 'int' to 'Student'
//Student.h
class Student
{
private:
int id;
std::string name;
public:
Student() { id = 0; name = ""; }
Student(int newId, std::string newName) { id = newId; name = newName; }
friend bool operator >= (const Student l, const Student& r)
{
return std::tie(l.id, l.name) < std::tie(r.id, r.name);
}
friend bool operator == (const Student l, const Student& r)
{
return std::tie(l.id, l.name) < std::tie(r.id, r.name);
}
friend bool operator < (const Student l, const Student& r)
{
return std::tie(l.id, l.name) < std::tie(r.id, r.name);
}
friend bool operator > (const Student l, const Student& r)
{
return std::tie(l.id, l.name) < std::tie(r.id, r.name);
}
/*
Student& operator = (Student& t_id)
{
if(this != &t_id)
id = t_id.getId();
return *this;
}
*/
void getStudent() { std::cin >> id; }
int getId() const { return id; }
void setId(int t_id) { id = t_id; }
std::string getName() const { return name; }
void setName(std::string t_name) { name = t_name; }
//ItemType getGpa() const { return gpa; }
//virtual void setGpa(std::string t_gpa) { gpa = t_gpa; }
Do I need = operator to fix that problem?
Actually, I created the = operator but if I enable that = operator code,
the other codes with equal sign that are in other functions
encounter errors. (no viable overloaded '=')
How can I fix this errors?
Thank you for your helping.
Just see this line.
ItemType root = nodePtr->getItem().getId();
Do you feel that something is wrong here?

Outputting Vector of Type Class

There is more code to this question in this previous question: C++ Trouble Inputting Data into Private Vector (invalid use)
I'm trying to output a vector of type "Account"
Account:
class Account
{
string firstName;
string lastName;
string accountPass;
int accountID;
float accountBalance;
private:
int depositAmount;
int withdrawAmount;
public:
static Account createAccount( int, float, string, string, string ); //creates new account
void deposit( int ); //deposits money into account
void withdraw(int); //withdrawals money from account
int retdeposit() const; //function to return balance amount
friend class BankingSystem;
}; //end of class Account
This is the way I'm declaring the vector:
std::vector<Account> accounts_;
And here's how I'm trying to print it to the screen:
for(int i=0; i < accounts_.size(); i++)
{ cout<< accounts_[i] <<endl; }
But I'm getting this error "invalid operands to binary expression".
Current code;
class BankingSystem
{
int accountID;
char fileName;
private:
std::vector<Account> accounts_;
public:
void addAccount();
void storeAccount( Account );
void deleteAccount();
void accountInquiry();
void saveAccounts();
void loadAccountsFromFile();
friend class Account;
friend std::ostream& operator << (std::ostream&, const Account&);
}; // end of class BankingSystem
#endif
std::ostream& operator << (std::ostream& os, const Account& acc)
{
// output members to os
return os;
}
void BankingSystem::addAccount()
{
int ID;
float balance;
std::string pass, first, last;
cout << "\n\t Enter the Account ID: ";
cin >> ID;
cout << "\n\t Enter the passcode: ";
cin >> pass;
cout << "\n\t Enter Client's first name: ";
cin >> first;
cout << "\n\t Enter Client's last name: ";
cin >> last;
cout << "\n\t Enter starting balance: ";
cin >> setw(6) >> balance;
storeAccount( Account::createAccount( ID, balance, pass, first, last ) );
return;
}
//function gets data from createAccount
void BankingSystem::storeAccount( Account newAccountToAdd )
{
//append to vector "accounts_"
accounts_.push_back(newAccountToAdd);
}
void BankingSystem::deleteAccount()
{
cout << "\nEnter The Account ID: ";
cin >> accountID;
}
void BankingSystem::accountInquiry()
{
int n;
cout << "\n\t Enter The Account ID (-1 for all): ";
cin >> n;
//cout << accounts_.size();
if (n == -1)
{
cout << "\n\t List of all Accounts; (" << accounts_.size() << ") TOTAL: ";
for(int i=0; i < accounts_.size(); i++)
{
cout<< accounts_[i] << endl;
}
}
else
{
cout << "\n\t Listing Account: " << n;
cout << "\n\t I should search the vector for the ID you input";
}
}
You need to provide the insertion operator:
std::ostream& operator<<( std::ostream& out, const Account& acct );
Then implement it internally by dumping each one of the fields with the appropriate format.
You should overload operator << for Account class. In class:
friend std::ostream& operator << (std::ostream&, const Account&);
In global (or yours, where Account is defined) namespace
std::ostream& operator << (std::ostream& os, const Account& acc)
{
// output members to os
return os;
}
or create some output function in class for example
void print(std::ostream& os) const { }
And then free-operator <<
std::ostream& operator << (std::ostream& os, const Account& acc)
{
acc.print(os);
return os;
}

enum type can not accept cin command

Look t this code plz:
#include <iostream>
using namespace std;
int main()
{
enum object {s,k,g};
object o,t;
cout << "Player One: "; cin >> o;
cout << "Player Two: "; cin >> t;
if (o==s && t==g) cout << "The Winner is Player One.\n";
else if (o==k && t==s) cout << "The Winner is Player One.\n";
else if (o==g && t==k) cout << "The Winner is Player One.\n";
else if (o==g && t==s) cout << "The Winner is Player Two.\n";
else if (o==s && t==k) cout << "The Winner is Player Two.\n";
else if (o==k && t==g) cout << "The Winner is Player Two.\n";
else cout << "No One is the Winner.\n";
return 0;
}
while compiling I will get this error:no match for 'operator>>' in 'std::cin >> o
I'm using code-blocks. so what is wrong with this code?
There is no operator>>() for enum. You can implement one yourself:
std::istream& operator>>( std::istream& is, object& i )
{
int tmp ;
if ( is >> tmp )
i = static_cast<object>( tmp ) ;
return is ;
}
Of course, it would be easier if you just cin an integer and cast yourself. Just want to show you how to write an cin >> operator.
Do you expect to be able to type "s", "k", or "g" and have it parse those into your enum type? If so, you need to define your own stream operator, like this:
std::istream& operator>>(std::istream& is, object& obj) {
std::string text;
if (is >> text) {
if (text == "s") {
obj = s;
}
// TODO: else-if blocks for other values
// TODO: else block to set the stream state to failed
}
return is;
}
If you're not familiar with Operator Overloading concept and want a quick-fix, simply use:
scanf("%d%d", &o, &t);