Why cin stopped working after cin>>(int) failed? - c++

When cin>>(int) and cin>>(string) are called, when the first input is not correct for integer, it seems that cin>>(string) will fail to retrieve the second input even if it is correct string.
The source code is simple as:
cout<<"Please enter count and name"<<endl;;
int count;
cin>>count; // >> reads an integer into count
string name;
cin>>name; // >> reades a string into name
cout<<"count: "<<count<<endl;
cout<<"name: "<<name<<endl;
The test cases are:
Case 1: Type characters(which not fit for int) and characters
Please enter count and name
ad st
count: 0
name:
Case 2: Type numbers and characters
Please enter count and name
30 ad
count: 30
name: ad
Case 3: Type numbers and numbers (which could be taken as strings)
Please enter count and name
20 33
count: 20
name: 33

A stream has an internal error flag that, once set, remains set until you explicitly clear it. When a read fails, e.g. because the input could not be converted to the required type, the error flag is set, and any subsequent reading operation will not even be tried as long as you do not clear this flag:
int main() {
stringstream ss("john 123");
int testInt;
string testString;
ss >> testInt;
if (ss) {
cout << "good!" << testInt << endl;
} else {
cout << "bad!" << endl;
}
ss >> testString;
if (ss) {
cout << "good!" << testString << endl;
} else {
cout << "bad!" << endl;
}
ss.clear();
ss >> testString;
if (ss) {
cout << "good:" << testString << endl;
} else {
cout << "bad!";
}
}
Output:
bad!
bad!
good:john

You can check for the input statement if it is succeeded or not with the
cin.good() method
If the input statement fails it returns false else true. Here is a small example:
#include <iostream>
#include <cstdlib>
using namespace std;
int main()
{
int x;
// prompt the user for input
cout << "Enter an integer: " << "\n";
cout << "cin.good() value: " << cin.good() << "\n";
// get input
cin >> x;
cout << "cin.good() value: " << cin.good() << "\n";
// check and see if the input statement succeeded
if (!cin) {
cout << "That was not an integer." << endl;
return EXIT_FAILURE;
}
// print the value we got from the user
cout << x << endl;
return EXIT_SUCCESS;
}
Output:
Enter an integer:
cin.good() value: 1
asd
cin.good() value: 0
That was not an integer.

Related

Why does This program have a logical error

this is the code i wrote for simple grading exams (im still a very beginner) but when i do a wrong input in (Grades) it doesnt go to the function i made which is called (FalseInput) to make the user able to re-enter the (Grades) any suggestions to how to solve?
and how to improve in general ?
here is an example of whats the problem :
Please Type Your Name : rafeeq
Please Insert The Grade : as (which is an input error)
you failed
thanks.
#include <iostream>
#include <string>
using namespace std;
char Name[30];
int Grades;
const int MinGrade(50);
void FalseInput() {
cout << "pleae enter the number again : ";
cin >> Grades;
if (Grades >= MinGrade) {
cout << Name << " : " << "you passed\n";
cout << Grades;
} else if (Grades < MinGrade and cin.fail() == 0) {
cout << "you failed\n";
} else if (cin.fail() == 1) {
cout << "its not a valid number\n";
cin.clear();
cin.ignore(1000, '\n');
cout << endl;
FalseInput();
}
}
int main() {
cout << "Please Type Your Name : ";
cin.getline(Name, 30);
cout << "Please Insert The Grade : ";
cin >> Grades;
if (Grades >= MinGrade) {
cout << Name << " : " << "you passed\n";
cout << "The Grade Achieved : " << Grades << "%";
} else if (Grades < MinGrade) {
cout << "you failed\n";
} else if (cin.fail() == 1) {
cout << "its not a valid number\n";
cin.clear();
cin.ignore(1000, '\n');
cout << endl;
FalseInput();
}
return 0;
}
You don't check if the extraction of an int succeeds here:
cin >> Grades;
You can check the state of the input stream after extraction like this and it needs to be the first condition or else the program will make the comparisons with MinGrade first and will get a true on Grades < MinGrade.
if(!(cin >> Grades)) {
if(cin.eof()) {
// You can't recover the input steam from eof so here you need
// to handle that. Perhaps by terminating the program.
}
cin.clear();
cin.ignore(1000, '\n');
cout << endl;
FalseInput();
} else if(Grades >= MinGrade) {
cout << Name << " : " << "you passed\n";
cout << "The Grade Achieved : " << Grades << "%";
} else if(Grades < MinGrade) {
cout << "you failed\n";
}
You do have a lot of unnecessary code duplication and you also use an array of char to read the name - but you have included <string> so I assume you're familiar with std::string. I suggest using that.
Simplification:
#include <iostream>
#include <limits>
#include <string>
int main() {
const int MinGrade = 50;
std::string Name;
int Grades;
std::cout << "Please Type Your Name : ";
if(std::getline(std::cin, Name)) {
while(true) {
std::cout << "Please Insert The Grade : ";
if(!(std::cin >> Grades)) {
if(std::cin.eof()) {
std::cout << "Bye bye\n";
break;
}
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "That's not a valid number!\nPlease enter the "
"number again!\n";
} else if(Grades >= MinGrade) {
std::cout << Name << " : " << "you passed\n";
std::cout << "The Grade Achieved : " << Grades << "%\n";
break;
} else { // no need to check "Grades < MinGrade" here
std::cout << "you failed\n";
break;
}
}
}
}
What is happening: When that string "as" is attempted to write to the integer Grades, cin.fail() is set and Grades has the default of 0 written to it (I think that's right)
C++ cin reading string into int type returns 0
All-in-All: Input validation is needed BEFORE you check it's values.
Here is one approach, check if cin was able to successfully convert:
https://www.hackerearth.com/practice/notes/validating-user-input-in-c/
Another approach would be to read cin into a string instead of int, then you can control how to convert/cast it to whatever form you want (more work, but being that you are new - you will learn a lot doing this).
Secondary Note: Your string of 50 characters for name - imagine what would happen if you wrote 60 characters of input. There will be more data than the container can hold, thus writing past the bounds and into his neighbor (could cause a segment fault, or worse - crazy unexpected behavior)
Why does this work? Using cin to read to a char array smaller than given input

The while loop keeps executing no matter whatever the second user input is within the second case of the switch

The code has been updated in order to solve a different section of the whole picture within the coding process. Now I need help within the second case of the switch. The problem now is that the while loop always executes within the second function of the switch. I don't no if the array is verifying the number or the user input.. I could use while (string::npos != studID2[i].find_first_of(studID2[a])) I need some help here it is getting very complex and I am hitting a brick wall.
1)I need to verify each user input using a for loop and two arrays. I tried to increment the of the arrays in order to execute the while statement.
2) If the condition is true the while loop will execute telling the user that he must enter 3 different digits, the reason why I am using an array and a for loop is because the user gets to choose how many names and IDs he would like to input into the archive.
3) The for loop increments a++ in order to check to see if the last input is the same as the newest user input.
It is getting too complex here any help would be appreciated.
Number 4 is the expected error...
4) The second user input will always make the while loop run regardless of what digits you use.
5)The reason for so much code is because I am not completely sure where the problem begins and the problem ends...
6)I am using two arrays here in this problem.
7)There is another error if you change the a from 0 to 1 it will automatically close the program. The reason you would change the a to a 1 is so that a will increment by 1.
//I am trying to verify multiple inputs with a array and a for loop..
// The expected output is that the second ID you input in the second option of the switch case is going to execute the while loop.
//I am trying to execute the while loop properly within the second function of the switch case.
//I need help any form of help can be appreciated.
#include<iostream>
#include<string>
#include<fstream>
#include<sstream>
#include <cstddef>
#include <limits>
#include <cstdlib>
int name2 = 0;
int studentID = 0;
int email2 = 0;
int studentID2[100];
std::string let("abcdefghijklmnopqrstuvwxyz");
int numbers = (1, 3, 0);
std::string str;
std::string name;
std::string studID;
std::string studID2;
std::string email;
std::string emailbackup;
std::string studFinal;
std::stringstream concatenate;
std::stringstream concatenatetwo;
int x;
std::string fileName = "StudentArchive.txt";
void emailEntry();
void readDocument();
int readNumber();
void deleteInformation();
void getStudentinformation();
using std::cout;
using std::cin;
int main()
{
do {
std::cout << "What would you like to do?" << std::endl;
std::cout << "1)Would you like to see the archive?" << std::endl;
std::cout << "2)Would you like to register student information?" << std::endl;
std::cout << "3)Would you like to find a student within the registry?" << std::endl;
std::cout << "4)Delete all student information?" << std::endl;
std::cout << "5)Exit Program?" << std::endl;
std::cin >> x;
switch (x)
{
case 1:
readDocument();
break;
case 2:
emailEntry();
break;
case 3:
deleteInformation();
break;
case 4:
getStudentinformation();
break;
case 5:
cout << "Exiting Program." << std::endl;
system("PAUSE");
break;
}
} while (x != 5);
}
void emailEntry()
{
std::ofstream outfile;
outfile.open(fileName, std::ios_base::app);
int amountofStudent;
std::cout << "How many student Identities would you like to enter?" << std::endl;
std::cin >> amountofStudent;
cin.ignore();
Here is where the user chooses how many students he would like to enter into the registry. I am having difficulty verifying the user input regarding the studentIDs.
if (outfile.is_open()) {
for (int i = 0; i < amountofStudent; i++)
{
std::string studID2[100];
std::stringstream(name) >> name2;
cout << "Please enter your name.." << std::endl;
getline(cin, name);
outfile << name;
std::stringstream(name2) >> name;
while (std::string::npos != name.find_first_of("0123456789"))
{
cout << "You must have letter within user input." << std::endl;
cout << "Please enter your name." << std::endl;
getline(cin, name);
outfile << name;
}
//I need to check to see if the first 3 numbers are correct?
//The student ID must be at least 6 digits, and the first 3 numbers must be 130.
cout << "Please enter Your student I.D." << std::endl;
getline(cin, studID);
outfile << studID;
std::stringstream(studID) >> studentID;
while (/*std::string::npos != studID.find_first_of("130") */ studentID != 130 /*&& studID.length() <= 6*/)
{
std::stringstream(studentID) >> studID;
cout << "You must enter 130 as the first 3 digits" << std::endl;
getline(cin, studID);
std::stringstream(studID) >> studentID;
}
//==============
//std::stringstream(studentID2) >> studID2[i];
cout << "Please enter the second part of the student I.D. " << studentID << "-" << std::endl;
getline(cin, studID2[i]);
outfile << studID;
//outfile << studID2[i];
std::stringstream(studID2[i]) >> studentID2[i];
//cout << i;
This is the for loop, and array I need help with. Below this text is where I am having problems. I don't understand why the while loop won't execute I am trying to verify the first user input with the next user input. For example if the user enters 888 on the first input then tries to enter 888 on the second input they need to re-enter different digits or the input will go on forever. The main struggle is if the user chooses to enter multiple student accounts within this minor registry.
for (int a = 0; a < i; i++)
{
while (studID2[i] == studID2[a])
{
cout << "The numbers cannot be repeated you must re-enter the student ID." << std::endl;
std::stringstream(studentID) >> studID;
cout << "You must enter 130 as the first 3 digits" << std::endl;
getline(cin, studID);
std::stringstream(studID[i]) >> studentID;
//std::stringstream(studID2[i]) >> studentID2;
cout << "Please enter the second part of the student I.D. " << studentID << "-" << std::endl;
getline(cin, studID2[i]);
outfile << studID;
outfile << studID2[i];
//std::stringstream(studID2[i]) >> studentID2;
}
}
This is where the verification of the studentIDs end...
while (/*std::string::npos != studID.find_first_of("130") */ studID2[i].length() < 3 || studID2[i].length() > 3)
{
//stringstream(studentID) >> studID;
cout << "Add 3 more digits." << std::endl;
getline(cin, studID2[i]);
outfile << studID2[i];
}
concatenate << studentID << "-" << studID2 << std::endl;
studFinal = concatenate.str();
/*while (studID.length() != 6)
{
cout << "You must enter 130 as the first 3 digits and you must have 6 digits." << std::endl;
std::cin >> studID;
}*/
cout << "Please enter your email.." << std::endl;
std::stringstream(email) >> email2;
getline(cin, email);
outfile << email;
std::stringstream(email2) >> email;
while (email == emailbackup || email.empty())
{
cout << "Please enter your email..." << std::endl;
std::stringstream(email) >> email2;
getline(cin, email);
outfile << email;
std::stringstream(email2) >> email;
}
concatenatetwo << email << "#atlanticu.edu" << std::endl;
email = concatenatetwo.str();
emailbackup = email;
cout << "Your email is" << email << std::endl;
std::system("pause");
}
}
outfile.close();
}
Here is where the user deletes info..
void deleteInformation()
{
std::ofstream infile(fileName, std::ios::trunc);
if (infile.is_open()) {
cout << "You have now have no books." << std::endl;
system("PAUSE");
system("cls");
infile.close();
}
}
void getStudentinformation()
{
std::ifstream outfile;
outfile.open(fileName);
if(outfile.is_open())
{
int x;
cout << "1)Name" << std::endl;
cout << "2)studentNumber" << std::endl;
cout << "3)Exit" << std::endl;
cin >> x;
switch (x)
{
case 1:
cout << "Please enter the student's name.." << std::endl;
getline(cin, name);
cout << name << std::endl;
outfile >> name;
break;
case 2:
cout << "Please enter the first 3 digits of the student's ID number.. " << std::endl;
getline(cin, studID);
cout << "Please enter the last 3 digits of the student's ID number.. " << std::endl;
getline(cin, studID2);
outfile >> studID;
outfile >> studID2;
break;
case 3:
std::string choice;
cout << "Would you like to return to the main menus?" << std::endl;
cin >> choice;
break;
}
}
}
int readNumber()
{
int number;
cin >> number;
std::string tmp;
while (cin.fail())
{
cin.clear();
std::getline(cin, tmp);
cout << "Only numbers please: ";
cin >> number;
}
getline(cin, tmp);
return number;
}
Here is where the user reads the txt doc.
void readDocument()
{
std::ifstream infile;
infile.open(fileName);
if (infile.is_open()) {
std::string info;
while (getline(infile, info))
{
cout << info << std::endl;
}
infile.close();
}
else {
cout << fileName << " doesn't exists !" << std::endl;
}
std::system("PAUSE");
std::system("cls");
}
//std::ofstream outfile;
//outfile.open(fileName, ios_base::app);
//if(outfile.is_open()) {
// cout << "How many books do you want to add: ";
// int n = readNumber();
// while (n <= 0)
// {
// cout << "Only positive numbers, please: ";
// n = readNumber();
// }
// for (int i = 0; i < n; i++) {
// string title = "Book's Title: ";
// cout << title;
// title += readText();
// string author = "Author: ";
// cout << author;
// author += readText();
// string genre = "Book's Genre: ";
// cout << genre;
// genre += readText();
// cout << endl;
// outfile << title << endl;
// outfile << author << endl;
// outfile << genre << endl << endl;
// }
//}
// outfile.close();
// cout << "Books have been added to the library !" << endl;
// system("PAUSE");
// system("cls");
Think about your function signature.
void email(string emailbackup);
Do you actually want the caller to pass a string to the function email()?
Because you then define emailbackup inside the function again.
You want something like this probably...
...
case 2:
const string backup = "backup#email";
email(backup);
break;
...
void email(string emailbackup)
{
// string emailbackup; // delete this line
...
}
Also, remove using namespace std; and be consistent with your namespace usage. Why add using namespace cout, cin etc if you are calling them with the namespace explicitly i.e. std::cin, std::cout.
Either add using namespace std::cout and use cout rather than std::cout or vice versa. Don't mix it up. Same with std::string and string. Makes it look like you defined your own string...
Just one last thing, for the sake of readability I would suggest breaking this email function into smaller functions. For instance:
void email(string emailbackup)
{
...
int studentID = getStudentID();
string studentEmail = getStudentEmail();
...
}
int getStudentID()
{
int studentID;
cout << "Please enter Your student I.D." << std::endl;
std::cin >> studID;
stringstream(studID) >> studentID;
while (/*std::string::npos != studID.find_first_of("130") */ studentID != 130 /*&& studID.length() <= 6*/)
{
stringstream(studentID) >> studID;
cout << "You must enter 130 as the first 3 digits" << std::endl;
std::cin >> studID;
stringstream(studID) >> studentID;
}
return studentID;
}

C++ I/O stream issue: program asks for input twice or work incorrectly

I'm trying to write a program that reads input as int from the command line, and if the user enters an int, program prints "Input is " + the number if users enter an incorrect type input, output "wrong input".
Here is my code:
#include <iostream>
#include <string>
using namespace std;
int main() {
int input;
cout << "Enter an Int:" << endl;
cin >> input;
if (!(cin >> input)) {
cout << "wrong format input" << endl;
return 1;
}
cout << "input is " << input << endl;
return 0;
}
Now with cin >> input; (case-1) program asks for twice input when enter correct integer; it prints "wrong format input" if user enter '2.2' or 'a'.
Without cin >> input; (case-2) program ask for once input when enter correct integer; but it prints "input is 2" when user enter '2.2', instead of printing "wrong" message, program prints "Input is 2".
Which part in my code did I make mistake? How can I fix this?
For case-2:
Here is the sample that allows to enter several integers on the same line, but disallows anything else
#include <iostream>
#include <string>
int main()
{
std::string input;
while(std::cin >> input){
size_t last;
int res;
bool good = true;
try{
res = std::stoi(input,&last);
}
catch(...){
good = false;
}
if(!good || last != input.length()){
std::cout << "Incorrect input: " << input << ", try again.\n";
}
else{
std::cout << "Integer read: " << res << '\n';
}
}
return 0;
}
/***************
Output
$ ./test
2
Integer read: 2
hello
Incorrect input: hello, try again.
2.2
Incorrect input: 2.2, try again.
1111111111111111111111111111111111111111111111111111111111111111111111
Incorrect input: 1111111111111111111111111111111111111111111111111111111111111111111111, try again.
3 4
Integer read: 3
Integer read: 4
^Z
[3]+ Stopped ./test
*/
Another version - using stringstream
while(std::cin >> input){
std::istringstream ss(input);
int res;
ss >> res;
if(!ss){
std::cout << "Incorrect input: " << input << ", try again.\n";
}
else{
char ch = ss.get();//let's check that no more characters left in the string
if(!ss){
std::cout << "Integer read: " << res << '\n';
}
else{
std::cout << "Incorrect input: " << input << ", try again.\n";
}
}
}
if(!(cin >> input)) is the reason for the second input. Just do this:
#include <iostream>
#include <string>
using namespace std;
int main() {
int input;
cout << "Enter an Int:" << endl;
cin >> input;
if (cin.fail()) {
cout << "wrong format input" << endl;
return 1;
}
cout << "input is " << input << endl;
return 0;
}

extract cin data to a variable that fits

In case of an invalid input, I want extract the invalid input from cin and store it in a variable that fits. How can I do that?
#include<iostream>
using namespace std;
int main(){
int number;
cout << "Enter a number: " << endl;
cin >> number;
if(cin.fail()){
cout << "Error!" << endl;
//HOW CAN I STORE THE INVALID INPUT WHICH IS STORED IN cin INTO A STRING?
}
return 0;
}
When you detect that failbit is set, reset it, and use std::getline to read entire line of invalid input into std::string from std::cin:
#include <iostream>
#include <string>
int main()
{
int number;
while(true)
{
std::cout << "Enter a number (0 to exit): " << std::endl;
std::cin >> number;
if(std::cin.fail())
{
std::string error_data;
std::cin.clear(std::cin.rdstate() & ~std::ios::failbit);
std::getline(std::cin, error_data);
std::cout << "You didn't enter a number - you've entered: " << error_data << std::endl;
}
else
{
std::cout << "Number is: " << number << std::endl;
if(number == 0)
{
break;
}
}
}
return 0;
}

Invalid input in C++ stream

Consider the following code which takes an integer input and then prints the cin stream state:
#include <iostream>
using namespace std;
int main()
{
int number;
cout<<"Enter a number \n";
cin>>number;
cout<<cin.rdstate()<<endl;
return 0;
}
If the number entered is "zzzz" then the rdstate returns a value of 4.
If the number entered is "10zzzz" then the rdstate returns a value of 0, number has a value of 10, and the input stream has "zzzz" in it.
My question is:
1. Why isn't a input of "10zzzz" treated as an invalid input (atleast one of the failure bits should have been set.)
2. What is an elegant solution to detect and handle this situation.
Thanks!!!
First of all I would like to ask what you are trying to do with:
cout<<cin.rdstate()<<endl;
Read this page for the proper use of rdstate()
http://www.cplusplus.com/reference/iostream/ios/rdstate/
second:
to check wetether the input is either stringtype or integer type you might want to add something extra wich will convert the input string to integer data and will respond with an error message when feeded an invalid input.
therefor this will help you out:
int main() {
string input = "";
// How to get a string/sentence with spaces
cout << "Please enter a valid sentence (with spaces):\n>";
getline(cin, input);
cout << "You entered: " << input << endl << endl;
// How to get a number.
int myNumber = 0;
while (true) {
cout << "Please enter a valid number: ";
getline(cin, input);
// This code converts from string to number safely.
stringstream myStream(input);
if (myStream >> myNumber)
break;
cout << "Invalid number, please try again" << endl;
}
cout << "You entered: " << myNumber << endl << endl;
// How to get a single char.
char myChar = {0};
while (true) {
cout << "Please enter 1 char: ";
getline(cin, input);
if (input.length() == 1) {
myChar = input[0];
break;
}
cout << "Invalid character, please try again" << endl;
}
cout << "You entered: " << myChar << endl << endl;
cout << "All done. And without using the >> operator" << endl;
return 0;
}