The following code contains a logical error
every time i run it and enter 1 or 0 the code
in the while loop is still executed.
can someone tell me why?
bool getmove()
{
bool move;
cout << "Would you like to make the first move?(1 for yes 0 for no)\n";
cin >> move;
while(move != 1 || move != 0 || !cin.good())
{
if(!cin.good())
{
cout << "ERROR please try again\n";
cin.clear();
cin.ignore(80,'\n');
cin >> move;
}
else
{
cout << "Invalid input please try again\n";
cin >> move;
}
}
return move;
}
Look at this line:
while(move != 1 || move != 0 || !cin.good())
It will always be the case that move != 1 || move != 0 (because it can't be both).
Furthermore, you'll avoid some trouble by reading in something like a string and testing that, rather than relying on casting.
If you're trying to write a function which can validate the input of a boolean value, your code can be simplified to:
bool getmove()
{
bool move;
cout << "Would you like to make the first move?(1 for yes 0 for no)\n";
while (!(cin >> move))
{
cout << "Invalid input please try again\n";
cin.clear();
cin.ignore(80, '\n');
}
return move;
}
It is important to realize that while (!(cin >> move)) will repeat the loop until a valid boolean value can be read from the console and written into move.
Related
This small segment of my program seems to cause some problems:
cout << "Would you like to change the values? Type 1 if yes or 2 if no." << endl << "You can also reverse the original vector above by typing 3. \n Answer: ";
cin >> yesorno;
while (yesorno != 1 && yesorno != 2 && yesorno != 3 || cin.fail() )
{
cout << "\n Sorry, didn't catch that. Try again: ";
cin >> yesorno;
}
The loop works fine for all valid integers as far as I know, but when an unvalid value gets declared to yesorno the loop freaks out. For example, if I input the letter A, the loop goes on for infinity.
I guess what I'm asking is, how do I make it so that the user gets unlimited amounts of chances to input a valid value?
I'm pretty new to C++ btw so I am not familiar with all different kinds of public member functions etc.. I've tried cin.clear() but didn't have much success
When you run into error in reading input data, you may use cin.clear() to clear the state of the stream and follow it with a call to cin.ignore() to ignore the rest of the line.
while ( (yesorno != 1 && yesorno != 2 && yesorno != 3) || cin.fail() )
{
cout << "\n Sorry, didn't catch that. Try again: ";
if ( cin.fail() )
{
cin.clear();
cin.input.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
cin >> yesorno;
}
Another approach, that I prefer, is to read the input line by line and process each line independently.
std::string line;
while ( getline(cin, line) )
{
std::istringstr str(line);
if ( !(str >> yesorno) || (yesorno != 1 && yesorno != 2 && yesorno != 3) )
{
cout << "\n Sorry, didn't catch that. Try again: ";
continue;
}
else
{
// Got good input. Break out of the loop.
break;
}
}
When the fail bit gets set, you need to clear it before continuing.
while (yesorno != 1 && yesorno != 2 && yesorno != 3 || cin.fail() )
{
if ( cin.fail() ) {
cin.clear();
cin.ignore( std::numeric_limits<std::streamsize>::max() );
}
cout << "\n Sorry, didn't catch that. Try again: ";
cin >> yesorno;
}
Can you not use cin and then cin.fail() in the same line like this? Is there a cleaner or more standard way to do this type of error checking upon input?--perhaps not using a do-while.
do {
cin.clear();
cout << "\nPlease enter the size of the array (1-10): ";
} while (cin >> array_size && array_size <= 1 || array_size >= 10 || cin.fail());
This one works:
do {
cout << "Please input #: ";
if (cin.fail()){
cin.clear();
cin.ignore(80, '\n');
}
cin >> kids_total;
} while (cin.fail() || kids_total <= 0);
cin >> array_size && array_size <= 1 || array_size >= 10 || cin.fail()
Say you've got a letter next in cin, cin >> array_size evaluates false so the && short-circuit evalusation skips over array_size <= 1 to test:
array_size >= 10: might be uninitialised memory read ==> undefined behaviour, otherwise presumably false
cin.fail() - definitely true
...unless there's undefined behaviour - and maybe even then - the loop will continue without having removed the letter from cin, only to fail again immediately.
Check cin.ignore for a way to remove input that's failed parsing, or use std::getline(std::cin, my_string), std::istringstream iss(my_string); if (iss >> array_size etc. for a way to guarantee the entire line's thrown away on bad input....
For comparison, this is pretty robust and IMHO intuitive if verbose. If doing it more than once, just create a function....
while (true)
{
std::cout << "Please input #: ";
if (std::cin >> kids_total)
{
if (kids_total > 0)
break;
std::cout << "Value must be > 0, please try again.\n";
}
else if (std::cin.eof())
{
// rare for keyboard input - e.g. ^D on UNIX/Linux, ^Z Windows
// can happen with pipes/redirects - e.g. echo 10 20 | ./my_app
std::cerr << "expected value for kids_total but encountered end of input\n";
exit(EXIT_FAILURE);
}
else
{
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
I wish to achieve to limit user on only 0 or 1 when program asking for boolean variable.
I'we tried to do so, but it doesn't work. It still keep asking me for typing in.
bool ele;
do{
cout << "Elektro:\t";
cin >> ele;
if (cin && ele == 0 && ele == 1) break;
cin.clear();
cout << "Neveljaven vnos!" << endl;
}while(true);
The good news is, that operator>> for bool by default allows only '0' or '1' as valid input. That means you don't need to explicitly check the value after read - if stream state is ok, so is your bool:
bool ele;
if (!(cin >> ele)) {
// error;
}
The reason you're getting an infinite loop when you enter something like "cvdsavd" is that you only clear the error flags, but don't get rid of the bad charaters. So your loop keeps trying but never can get a valid input. You need to get rid of the garbage:
bool ele;
while (!(std::cin >> ele)) {
std::cout << "Neveljaven vnos!\n";
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
Reference for ignore(). You also need to include <limits> for numeric_limits template.
Lp :)
As chris points out, you want to do if (cin && (ele == 0 || ele == 1)) break;
You cant do that :
if (cin && ele == 0 && ele == 1) break;
because its always false because ele cant be in same time 1 or 0 ... It can be only one of this figures.
if(ele == 0 || ele == 1) break;
I have a while loop here that only takes in 1 and 2 as the number, if i insert and number that is not these my else statement will keep asking for the correct one, which works correctly. But if i insert a letter my else statement loops forever. How can i fix this?
#include <iostream>
using namespace std;
int main()
{
int myChoice;
cin >> myChoice;
while ( myChoice >= 2 || myChoice <= 1)
{
if (myChoice == 1)
{
cout <<"food1";
break;
}
else if (myChoice == 2)
{
cout <<"food2";
break;
}
else
{
cout << " " << endl;
cout << "Please select the proper choices" << endl;
cout << "Try again: ";
cin >> myChoice;
}
}
return 0;
}
If you enter a non-number, then cin >> myChoice fails. That means that it leaves the input intact in the input buffer and when you get there again it tries to parse it and fails, and so on... You must clear the error state and ignore the non-digits. The simplest way is something like this:
cout << "Try again: ";
cin.clear(); // clear error state
cin.ignore(std::numeric_limits<streamsize>::max(), '\n'); // ignore till the end of line
cin >> myChoice;
The problem here is that the cin >> operator expects to receive an int input and receives a char input.
The istream module, of which cin is an instance, is using buffered I/O. This means that the user input is first stored in a buffer, and then read from that buffer when the user program accesses the >> operator. Ordinarily, if the >> operator succeeds in reading and parsing the user input, the read data is extracted from the buffer and the next invocation of the >> operator would continue where the last call left off. In you case, however, the >> operator attempts to parse the user input as a number and fails since it contains illegal chars which are not digits. The >> operator doesn't extract the read data from the buffer in this case and this same data is being referred to over and over again in the following calls to the >> operator.
You should empty the buffer on failure, the way ybungalobill suggested, for instance.
Your while condition is always true, then you use break to exit the loop. You could simplify things a bit like this:
#include <iostream>
using namespace std;
int main()
{
int myChoice;
cin >> myChoice;
while( myChoice != 1 || myChoice != 2 ) {
cout << endl;
cout << "Please select the proper choices" << endl;
cout << "Try again: ";
cin.clear();
cin.ignore(std::numeric_limits<streamsize>::max(), '\n');
cin >> myChoice;
}
// At this point myChoice is 1 or 2
if (myChoice == 1)
cout << "food1";
else if (myChoice == 2)
cout << "food2";
}
I'm trying to filter out invalid user inputs in a small C++ program using the following chunk of code:
int selection = -1;
while (!(selection >= 1 && selection <=4))
{
cin >> selection;
if (!(selection >= 1 && selection <=4))
{
cout << "invalid selection!" << endl;
cout << "selection: ";
}
}
It seems to work fine when I enter any numerical value that is either inside or outside the range i want to filter. However strange things happen when I enter invalid values such as values larger than the maximum storable int or characters. The code loops through and skipping the "cin" command.
How do I fix this?
Thanks
You need to detect unconvertible input using fail() and then ignore the rest of the bad data and reset cin error flags using clear() before reading in a new input attempt.
int selection = -1;
while (!(selection >= 1 && selection <=4))
{
cin >> selection;
if (cin.fail() || !(selection >= 1 && selection <=4))
{
cout << "invalid selection!" << endl;
cout << "selection: ";
cin.clear();
cin.ignore(std::numeric_limits<int>::max(), '\n');
}
}
Here are two suggestions for fixing your issue:
Add Error Handling to cin
Read as String And Parse
The common solution is Read As String And Parse, but I'm presenting both for you to choose.
Add Error Handling to cin
When the stream extraction function receives a character that is not suited for numerics, it sets a fail bit. You need to check the state of the stream (cin) for failure. If you want to continue, you need to clear the error state.
The state can be checked by using the fail method: cin.fail(). To clear the state use: cin.clear().
See C++ Online Reference -- istream
Read As String And Parse
An alternative is read the input as a string, then parse the string for your data. The string container has some useful methods for parsing.
Use getline to read in a string variable from cin.
Again, you will have to write code to check for errors and process them.
You need to check condition of cin, and if it is any error states, you should clear the error flag and ignore():
int main()
{
int selection = -1;
while (!(selection >= 1 && selection <=4))
{
if (cin >> selection)
{
if (!(selection >= 1 && selection <=4))
{
cout << "invalid selection!" << endl;
cout << "selection: ";
}
}
else
{
cin.clear();
cin.ignore();
}
}
cout << selection << " selected\n";
return 0;
}
Another way is to read everything as string and let the stringstream do error check:
int main()
{
int selection = -1;
while (!(selection >= 1 && selection <=4))
{
string line;
getline(cin, line);
stringstream sstr(line);
if (sstr >> selection)
{
if (!(selection >= 1 && selection <=4))
{
cout << "invalid selection!" << endl;
cout << "selection: ";
}
}
else
{
cout << "invalid input!" << endl;
cout << "selection: ";
}
}
cout << selection << " selected\n";
return 0;
}
Note: You may need to put a cin.ignore(); right after getline() call - depending on if you are reading all unformatted input or not.
You should read cin into a std::string and start your validation from there. Check that the value is numeric, for starters.
When you enter letters for example it puts cin into a bad state and leaves those characters. You need to ignore them (cin.ignore(1024, '\n')) so it knows to move on to the next line of input.