When an input statement is requesting input of one type, and erroneous input or input of another type is provided, the error state of the input stream is set to ios::badbit and ios::failbit, and further input operations may not work properly. For example, the following code repeatedly displays the text: Enter an integer value: if the first input provided is a string whose initial characters do not form an integer value:
#include <iostream.h> void main() { int i=-1; while (i<=0) { cout << "Enter a positive integer: " ; cin >> i; } cout << "The value was " << i << endl; }
This program loops indefinitely, given an input such as ABC12, because the erroneous input causes the error state to be set in the stream, but does not clear the error state or advance the get pointer in the stream beyond the erroneous characters. Each time the input operator is called for an int (as in the while loop above), the same characters are read in.
To clear an input stream and repeat an attempt at input you must add code to do the following:
You can determine whether the stream's error state has been set in one of the following ways:
You can clear the error state by calling clear(), and you can remove the erroneous characters using ignore(). The example above could be improved, using these suggestions, as follows:
#include <iostream.h>
void main() { int i=-1; while (i==-1) { cout << "Enter an integer value: "; cin >> i; while (cin.fail()) { // could also be "while (!cin) {" cin.clear(); cin.ignore(1000,'\n'); cerr << "Please try again: "; cin >> i; } } cout << "The value was " << i << endl; }
The ignore() member function with the arguments shown above removes characters from the input stream until the total number of characters removed equals 1000, or until the new-line character is encountered, or until EOF is reached. This example produces the output shown below in regular type, given the input shown in bold:
Enter an integer value: ABC12 Please try again: 12ABC The value was 12
Note that, for the second attempt at input, the error state is set after the input of 12, so the call to cin.fail() after the corrected input returns false. If another integer input were requested after the while loop ends, the error state would be set and that input would fail.
When you define an input operator of class type, you can build error-checking code into your definition. If you do so, you do not have to check for error-causing input every time you use the input operator for objects of your class type. Consider the class definition for the PhoneNumber data type shown in myclass.h, and the following input operator definition:
istream& operator>> (istream& aStream, PhoneNumber& aPhoneNum) { int AreaCode, Exchange, Local; aStream >> AreaCode; while (aStream.fail()) eatNonInts(aStream,AreaCode); aStream >> Exchange; while (aStream.fail()) eatNonInts(aStream,Exchange); aStream >> Local; while (aStream.fail()) eatNonInts(aStream,Local); aPhoneNum=PhoneNumber(AreaCode, Exchange, Local); return aStream; }
The eatNonInts() function in this example should be defined to ignore all characters in the input stream until the next integer character is encountered, and then to read the next integer value into the variable provided as its second argument. The function could be defined as follows:
void eatNonInts(istream& aStream, int& anInt) { char someChar; aStream.clear(); while (someChar=aStream.peek(), !isdigit(someChar)) aStream.get(someChar); aStream >> anInt; }
Now whenever input is requested for a PhoneNumber object and the provided input contains nonnumeric data, this data is skipped over. Note that this is only a primitive error-handling mechanism; if the input provided is 416 555 2p45 instead of 416 555 2045, the characters p45 will be ignored and the local is set to 2 rather than 2045. A more complete example would check each input for the correct number of digits.