Cin Input (Input Is an Int) When I Input a Letter, Instead of Printing Back Incorrect Once, It Prints Correct Once Then Inc for the Rest of the Loop

cin input (input is an int) when I input a letter, instead of printing back incorrect once, it prints correct once then inc for the rest of the loop

There are a number of ways to structure the various test, but when taking input with cin (or generally with any input function), you must account for any characters in the input buffer that remain unread. With cin, you have three conditions you must validate:

  1. .eof() (eofbit) is set. Either the end of input was reached, or the user manually generated an EOF by pressing Ctrl+d (or Ctrl+z on windoze, but see: CTRL+Z does not generate EOF in Windows 10);

  2. .bad() (badbit) is set. An unrecoverable stream error occurred; and

  3. .fail() (failbit) is set. A matching, or other recoverable, failure occurred. When the failure occurs input stops and no further characters are extracted from the input buffer.

(you can combine 1 & 2 into a single test as input is over at that point)

With failbit, you must do two things. (1) you must clear the stream error state by calling cin.clear(), and (2) you must handle any characters that remain unread in the input buffer. Generally this is handled by including <limits> and calling:

std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

(which will clear up to INT_MAX characters from the input buffer, stopping when the delimiter ('\n' here) is encountered)

A short example that loops until a valid integer is input by the user could be:

#include <iostream>
#include <limits>

using namespace std;

int main (void) {

int x = 0;

while (1) /* loop continually until valid input received */
{
cout << "\nenter an integer: ";
if (! (cin >> x) ) { /* check stream state */
/* if eof() or bad() break read loop */
if (cin.eof() || cin.bad()) {
cerr << "(user canceled or unreconverable error)\n";
return 1;
}
else if (cin.fail()) { /* if failbit */
cerr << "error: invalid input.\n";
cin.clear(); /* clear failbit */
/* extract any characters that remain unread */
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
}
else { /* on succesful read of int */
/* extract any characters that remain unread */
cin.ignore(numeric_limits<streamsize>::max(), '\n');
break; /* then break read loop */
}
}

cout << "integer: " << x << '\n';
}

(as mentioned at the beginning, you can structure the tests many different ways, as long as you cover all three conditions.)

Additionally, you can check the stream bit explicitly by calling rdstate() instead of testing with .fail(), etc..., e.g.

if (std::cin.rdstate() == std::ios_base::failbit)

Example Use/Output

$ ./bin/cin_validate_int

enter an integer: no
error: invalid input.

enter an integer: "an integer"
error: invalid input.

enter an integer: abc 123
error: invalid input.

enter an integer: 123
integer: 123

Look things over and let me know if you have further questions.

Why does while (true) skip cin when it received invalid input?

Once cin fails, it stays in an invalid state until it's cleared.

clear() without arguments can be used to unset the failbit after unexpected input

Sets the stream error state flags by assigning them the value of
state. By default, assigns std::ios_base::goodbit which has the effect
of clearing all error state flags.

As @Peter points out, you also have to clear the buffer.

Your example would be like this:

while (true) {
int x{0};
cout << "> ";
if (!cin) {
// unset failbit
cin.clear();
// clear the buffer
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
cin >> x;
cout << "= " << x << endl;
}

How cin works if user accidentally gives incorrect datatype?

If extraction fails, zero is written to value and failbit is set.

Input: 3.14

You read an integer. 3 is read and .14 remains in the buffer.

You read another integer. . is not a part of integer, therefore nothing is read and failbit is set.

You read a float. Nothing is read, because failbit is already set.

How do you write a program that tests if a user's inputs are integers and returns a message if they enter characters?

The function std::isdigit expects an int with the value of a character code. However, you are not passing it a character code. If you want to pass a character code, you must read the input as a string or as individual characters, not as a number. Otherwise, you will have no character codes to pass to std::isdigit.

However, unless the task description explicitly requires you to check that every single character is a digit, you don't have to call std::isdigit. This would also not be meaningful in some cases. For example, when the user enters negative numbers such as -34, the first character is not a digit. With this specific task, the user is not supposed to enter negative numbers, but the user may want to enter +34 for the number 34, which should also be valid (unless the task description explicitly states otherwise).

You have two options to solve this problem. You can either

  1. rely on the stream extraction operator >> and check whether an error occurred using std::cin.fail, or
  2. read one line of input as a string using std::getline, and use std::stoi to attempt to convert the string into to a number. The function std::stoi will tell you whether the input was valid or not, i.e. whether it was possible to convert the string to a number.

The first option may be easier to use, but the second option is generally recommended for line-based user input, as it will always read one line at a time.

However, both options do have one problem: They will accept input such as 6sdfh4q as valid input for the number 6. Therefore, if you want perfect input validation, you should also check the part of the input that was not converted to a number, to check whether it is acceptable. All whitespace characters are probably harmless, but all other characters are not, so I recommend that you use std::isspace for this purpose.

What if user inputs float in integer variable?

When you are using (cin>>number) as a condition, it will only be false if you enter a non-digit character. So in your case even if you enter a float, it will be false and the value of number = 2 (incase you enter 2.45).

Now the issue that you are facing is solved as follows :

int main(){

int number, number2, number3;

cout << "Enter a number: ";
while(!(cin >> number))
{
cout << "Wrong input! Enter a number: " << endl;
cin.clear();
cin.ignore(INT_MAX,'\n');
}
cout << "Enter number2 and number3: ";
cin.clear();
cin.ignore(INT_MAX,'\n');
cin >> number2; cin >> number3;
return 0;
}

This may be because it still has the some value in the input stream as it is not cleared, and it will pick that for number2 and number3.If I am using the above code as it is without cin.clear() and cin.ignore(INT_MAX,'\n') after the while loop, I am getting number2=0 and number3=0 as follows :

Enter a number: 2.45
Enter number2 and number3:
Value in number : 2
Value in number2 : 0
Value in number3 : 0

Not sure about it myself as well .Got the following output with this :

int main(){

int number, number2, number3;
string temp;
cout << "Enter a number: ";
while(!(cin >> number))
{
cout << "Wrong input! Enter a number: " << endl;
cin.clear();
cin.ignore(INT_MAX,'\n');
}
std::getline(std::cin, temp);
cout << "Enter number2 and number3: ";
// cin.clear();
// cin.ignore(INT_MAX,'\n');
cin >> number2; cin >> number3;
cout<<"Remaining in cin : "<<temp<<"\nValue in number : "<<number<<"\nValue in number2 : "<<number2<<"\nValue in number3 : "<<number3;
return 0;
}

Output :

Enter a number: 2.45
Enter number2 and number3: 2
3
Remaining in cin : .45
Value in number : 2
Value in number2 : 2
Value in number3 : 3

I hope someone could clear my doubt as well. Hope it was helpful.



Related Topics



Leave a reply



Submit