I ran into a problem while trying to validate my user input. Here's my code:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string choice;
cout << "Please type something: ";
cin >> choice;
cin.ignore();
while (choice != "1" && choice != "2" && choice != "3" && choice != "4" && choice != "5")
{
cout << "Incorrect choice! Please input a valid number: >_";
cin >> choice;
cin.ignore();
}
return 0;
}
When I input "wronginput", that input fell in the while loop and displayed
Incorrect choice! Please input a valid number: >_
Which is good. However, when I try "wrong input", I get a "weird" version of it:
Incorrect choice! Please input a valid number: >_ Incorrect choice! Please input a valid number: >_
My guess is that the space in between is the culprit. Is there any way for me to fix this? Thank you.
When you enter "wrong input" for input, the line
cin >> choice;
reads and stores "wrong" in choice.
The line
cin.ignore();
ignores only one character. Hence, you stull have "input" and the subsequent newline character in the stream. Next time you read into choice, you get "input" in choice.
That explains the behavior of your program.
In order to fix it, make sure to ignore the rest of the line instead of just one character. Use
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
Add
#include <limits>
to be able to use std::numeric_limits.
That's because std::cin >> choice is a formatted input that will read everything to the next whitespace.
When you type in "wronginput", it reads it all, but if you type in "wrong input", only the "wrong" part will be read. Your while loop will fire, perform std::cin >> choice inside its body once again and that will read "input".
This behaviour causes your program to output the message twice in a row.
How to fix it? Instead of reading a single token, up to the next whitespace, consider reading an entire line.
How to achieve that? Simply instead of using
std::cin >> choice;
use a std::getline function:
std::getline(std::cin, choice);
both outside and inside your while loop.
Related
I'm attempting to get a few user-input parameters from the console, two strings, two ints and a double. The relevant code I'm trying to use is this:
#include <string>
#include <iostream>
using namespace std;
// ...
string inputString;
unsigned int inputUInt;
double inputDouble;
// ...
cout << "Title: ";
getline(cin, inputString);
tempDVD.setTitle(inputString);
cout << "Category: ";
getline(cin, inputString);
tempDVD.setCategory(inputString);
cout << "Duration (minutes): ";
cin >> inputUInt;
tempDVD.setDuration(inputUInt);
cout << "Year: ";
cin >> inputUInt;
tempDVD.setYear(inputUInt);
cout << "Price: $";
cin >> inputDouble;
tempDVD.setPrice(inputDouble);
However, when running the program, instead of waiting for the first inputString to be entered, the code doesn't stop until the second getline() call. Thus the console output looks like this:
Title: Category:
with the cursor appearing after category. If I input now, the program then jumps ahead to the year input, not allowing me to enter more than one string. What's happening here?
The problem is you are mixing calls to getline() with the use of the operator >>.
Remember that operator >> ignored leading white space so will correctly continue across lines boundaries. But stops reading after the input has successfully been retrieved and thus will not swallow trailing '\n' characters. Thus if you use a getline() after a >> you usually get the wrong thing unless you are careful (to first remove the '\n' character that was not read).
The trick is to not use both types of input. Pick the appropriate one and stick to it.
If it is all numbers (or objects that play nice with operator >>) then just use operator >> (Note string is the only fundamental type that is not symmetric with input/output (ie does not play nicely)).
If the input contains strings or a combination of stuff that will require getline() then only use getline() and parse the number out of the string.
std::getline(std::cin, line);
std::stringstream linestream(line);
int value;
linestream >> value;
// Or if you have boost:
std::getline(std::cin, line);
int value = boost::lexical_cast<int>(line);
You need to flush the input buffer. It can be done with cin.clear(); cin.sync();.
You can use
cin.ignore();
or as #kernald mentioned use
cin.clear();
cin.sync();
before using getline()
Use cin.clear() as mentioned and use proper error handling:
cin.clear();
cin.sync();
cout << "Title: ";
if (!getline(cin, inputString)) exit 255;
tempDVD.setTitle(inputString);
cout << "Category: ";
if (!getline(cin, inputString)) exit 255;
tempDVD.setCategory(inputString);
cout << "Duration (minutes): ";
if (!(cin >> inputUInt)) exit 255;
tempDVD.setDuration(inputUInt);
cout << "Year: ";
if (!(cin >> inputUInt)) exit 255;
tempDVD.setYear(inputUInt);
cout << "Price: $";
if (!(cin >> inputDouble)) exit 255;
tempDVD.setPrice(inputDouble);
Also works with ws. You can use getline(cin >> ws, inputString)) to eat the whitespaces or the newlines after reading data with cin command.
If user inputs a space before \n in previous cin before getline, only ignore itself wouldn't be enough so you have to use this code instead of ignore() alone. For example 12345 \t \n will not work anymore.
All unprocessed characters must be ignored.
#include <limits>
cin.ignore(numeric_limits<streamsize>::max(), '\n');
Use this between cin and getline.
Mixing getline() with input streams in generally a bad thing to do. It's theoretically possible to manually handle the dirty buffers left over by using streams, but it's an unnecessary pain that should definitely be avoided.
You are better off using a console library to grab your input, this way the dirty-work can be abstracted for you.
Take a look at TinyCon. You can just use the static method tinyConsole::getLine() in replace of your getline and stream calls, and you can use it as many times as you'd like.
You can find information here:
https://sourceforge.net/projects/tinycon/
cin.sync();
use this instead of cin.ignore(
works best.
The function_______ will return the last read character and will move the inside pointer one with -1 char.
Getline()
Peek()
3.flush()
4.putback()
I'm new to C++ and I'm using Visual Studio 2015.
cin is not waiting for input after "Please enter another integer:\n" and outputs "You entered 0" every time.
I've searched the Internet more than an hour without a solution. No combination of cin.ignore() is working. Why is the cin buffer still not cleared?
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> vals;
int val = 0;
int n = 0;
cout << "Please enter some integers (press a non-numerical key to stop)\n";
while (cin >> val)
vals.push_back(val);
cin.ignore(INT_MAX, '\n');
cin.ignore();
cout << "Please enter another integer:\n";
cin.ignore();
cin >> n;
cout << "You entered " << n;
system("pause");
return 0;
}
The problem is for the user to exit the loop you need to put the cin in a failed state. That is why your
while(cin >> val){ .... }
is working.
If in a failed state cin is no longer in a position to supply you with input so you need to clear() the failed state. You also need to ignore() the previously non-integer response that triggered the failed state initially.
It would also be of merit to use
if(cin >> n){
cout << "You entered " << n;
}
This will assert that a proper input for n was provided.
The problem in your program is that it expects integers, whereas a user can input anything, like a non-integer char.
A better way to do what you seem to want to do is to read characters one by one, ignoring whitespace, and if it's a digit, then continue reading to get the whole number, else stop the loop. Then you can read all chars until you reach '\n', and do the same for one number. While you do that, for each character you should check that there can still be characters in the stream with cin.eof().
Also, instead of using system("pause"), you can prevent the command line window from closing by requesting a last character before terminating the application.
Try getting your integers like this :
#include <sstream>
...
fflush(stdin);
int myNum;
string userInput = "";
getline(cin, userInput);
stringstream s (userInput);
if (s >> myNum) // try to convert the input to int (if there is any int)
vals.push_back(myNum);
without sstream you have to use try catch, so your programme won't crash when input is not an integer
I don't think this question is not a duplicate of this. Even though it is caused by the same thing, it is a different manifestation of the problem.
The terminal output when I run this program looks like this (my input is 1 and Rock Lee followed by enter):
Enter a number: 1
Enter your name: Rock Lee
Name is blank.
However, the name shouldn't be blank. Why is the name variable ""? How do I fix this bug? Here is the code:
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
int main () {
int num;
string name;
cout << "Enter a number: ";
cin >> num;
cout << "Enter your name: ";
getline(cin, name, '\n');
cin.ignore (1000, '\n');
if (name == "")
{
cout << "Name is blank.";
return -1;
}
return 0;
}
Also, please note that I want to use Getline() in the solution, and I want to be able to read an entire line (so the name can be anything, not just first and last name).
When I tried commenting out cin.ignore(1000, '\n');, it gave this output which is also incorrect:
Enter a number: 1
Enter your name: Name is blank.
It doesn't even give me a chance to type in my name. How do I fix this?
cin >> num reads until it sees whitespace, but it doesn't discard the whitespace, so it leaves '\n' in the input. Your call to getline sees it and immediately returns, filling name with an empty string. You need to call cin.ignore before getline to ignore the '\n' that cin::operator>> left laying around.
Here Im trying to get an integer from user, looping while the input is correct.
After entering non integer value (e.g "dsdfgsdg") cin.fail() returns true, as expected and while loop body starts executing.
Here I reset error flags of cin, using cin.clear(); and cin.fail() returns false, as expected.
But next call to cin doesn't work and sets error flags back on.
Any ideas?
#include<iostream>
using namespace std;
int main() {
int a;
cin >> a;
while (cin.fail()) {
cout << "Incorrect data. Enter new integer:\n";
cin.clear();
cin >> a;
}
}
After cin.clear(), you do this:
#include <iostream> //std::streamsize, std::cin
#include <limits> //std::numeric_limits
....
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n')
What the above does is that it clears the input stream of any characters that are still left there. Otherwise cin will continue trying to read the same characters and failing
As a matter of style, prefer this method:
int main()
{
int a;
while (!(std::cin >> a))
{
std::cout << "Incorrect data. Enter new integer:" << std::endl;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
cin.clear() does not clear the buffer; it resets the error flags. So you will still have the sting you entered in your buffer and the code will not allow you to enter new data until you clear the cin buffer. cin.Ignore() should do the trick
There is also a very easy method:
#include <iostream>
std::cin.clear() //reset stream state so that cin.fail() becomes false.
std::cin.ignore(INT_MAX,'\n'); //clear the stream from any remaining characters until the \n which is present at the end of any cin.
This will reset stream state and clear any remaining things in it. Much easier, less code, and less header files.
I'm attempting to get a few user-input parameters from the console, two strings, two ints and a double. The relevant code I'm trying to use is this:
#include <string>
#include <iostream>
using namespace std;
// ...
string inputString;
unsigned int inputUInt;
double inputDouble;
// ...
cout << "Title: ";
getline(cin, inputString);
tempDVD.setTitle(inputString);
cout << "Category: ";
getline(cin, inputString);
tempDVD.setCategory(inputString);
cout << "Duration (minutes): ";
cin >> inputUInt;
tempDVD.setDuration(inputUInt);
cout << "Year: ";
cin >> inputUInt;
tempDVD.setYear(inputUInt);
cout << "Price: $";
cin >> inputDouble;
tempDVD.setPrice(inputDouble);
However, when running the program, instead of waiting for the first inputString to be entered, the code doesn't stop until the second getline() call. Thus the console output looks like this:
Title: Category:
with the cursor appearing after category. If I input now, the program then jumps ahead to the year input, not allowing me to enter more than one string. What's happening here?
The problem is you are mixing calls to getline() with the use of the operator >>.
Remember that operator >> ignored leading white space so will correctly continue across lines boundaries. But stops reading after the input has successfully been retrieved and thus will not swallow trailing '\n' characters. Thus if you use a getline() after a >> you usually get the wrong thing unless you are careful (to first remove the '\n' character that was not read).
The trick is to not use both types of input. Pick the appropriate one and stick to it.
If it is all numbers (or objects that play nice with operator >>) then just use operator >> (Note string is the only fundamental type that is not symmetric with input/output (ie does not play nicely)).
If the input contains strings or a combination of stuff that will require getline() then only use getline() and parse the number out of the string.
std::getline(std::cin, line);
std::stringstream linestream(line);
int value;
linestream >> value;
// Or if you have boost:
std::getline(std::cin, line);
int value = boost::lexical_cast<int>(line);
You need to flush the input buffer. It can be done with cin.clear(); cin.sync();.
You can use
cin.ignore();
or as #kernald mentioned use
cin.clear();
cin.sync();
before using getline()
Use cin.clear() as mentioned and use proper error handling:
cin.clear();
cin.sync();
cout << "Title: ";
if (!getline(cin, inputString)) exit 255;
tempDVD.setTitle(inputString);
cout << "Category: ";
if (!getline(cin, inputString)) exit 255;
tempDVD.setCategory(inputString);
cout << "Duration (minutes): ";
if (!(cin >> inputUInt)) exit 255;
tempDVD.setDuration(inputUInt);
cout << "Year: ";
if (!(cin >> inputUInt)) exit 255;
tempDVD.setYear(inputUInt);
cout << "Price: $";
if (!(cin >> inputDouble)) exit 255;
tempDVD.setPrice(inputDouble);
Also works with ws. You can use getline(cin >> ws, inputString)) to eat the whitespaces or the newlines after reading data with cin command.
If user inputs a space before \n in previous cin before getline, only ignore itself wouldn't be enough so you have to use this code instead of ignore() alone. For example 12345 \t \n will not work anymore.
All unprocessed characters must be ignored.
#include <limits>
cin.ignore(numeric_limits<streamsize>::max(), '\n');
Use this between cin and getline.
Mixing getline() with input streams in generally a bad thing to do. It's theoretically possible to manually handle the dirty buffers left over by using streams, but it's an unnecessary pain that should definitely be avoided.
You are better off using a console library to grab your input, this way the dirty-work can be abstracted for you.
Take a look at TinyCon. You can just use the static method tinyConsole::getLine() in replace of your getline and stream calls, and you can use it as many times as you'd like.
You can find information here:
https://sourceforge.net/projects/tinycon/
cin.sync();
use this instead of cin.ignore(
works best.
The function_______ will return the last read character and will move the inside pointer one with -1 char.
Getline()
Peek()
3.flush()
4.putback()