/////////////////////////////////////////////////////////////////////////////// // Three ways to read in an int w/o crashing. // // James Michael Matthew Hare // // January 30th, 2001 ///////////////////////////////////////////////////////////////////////////JMMH #include // for cin, cout, etc. #include // for atoi, etc. #include // for isalpha, isdigit, etc. #include // for string manipulation functions /////////////////////////////////////////////////////////////////////////////// // readIntUsingAtoi // // Accepts: istream, this is the input stream. Usually cin // // Returns: int,this is the int that was read in. // // This function reads an int from the screen and converts it using atoi, // this is probably the simplest version, but the problem is any non-valid // int may produce the number zero. Which may or may not be valid. // // We default to cin unless something else is specified ///////////////////////////////////////////////////////////////////////////JMMH int readIntUsingAtoi(istream & in = cin) { // need to read in as a string first char tempBuffer[256]; in.getline(tempBuffer, sizeof(tempBuffer)); // now convert from ascii to int (hence, atoi), and return the int. // the only problem is non-numerics will always return zero. return atoi(tempBuffer); } /////////////////////////////////////////////////////////////////////////////// // readIntUsingIStream // // Accepts: istream, this is the input stream. Usually cin // // Returns: int,this is the int that was read in. // // This function reads an int from the screen as an int, using the error, // handling functions of the istream to handle non numeric entries. This // solution requires more work. // // We default to cin unless something else is specified ///////////////////////////////////////////////////////////////////////////JMMH int readIntUsingIStream(istream & in = cin) { int result; // read in result as int bool error = false; // assume no errors yet. // keep doing it until they enter it right do { // read it error = false; in >> result; // if it failed, the fail flag will get set if(in.fail()) { // if this happens, we will set our error flag so we repeat. // then we must clear the flag and repeat. cerr << "I'm sorry, the format you entered is incorrect, try again : "; // If we don't clear the flag, in will bomb for rest of app in.clear(); // we then use ignore() to get rid of the offending character // ignore will ignore up to the specified # of chars, or until it hits a // specified delimeter (here, the new line) whichever happens first in.ignore(255, '\n'); error = true; } } while(error); // keep repeating as long as we have errors // we'll be nice and get rid of the ending chars in.ignore(255, '\n'); // return the number return result; } /////////////////////////////////////////////////////////////////////////////// // readIntUsingParsing // // Accepts: istream, this is the input stream. Usually cin // // Returns: int,this is the int that was read in. // // This function reads an int from the screen as an int, using a simple parser // This is probably the most robust form, but also the most complex. Most // work with reading ints in windows involves parsing. // // We default to cin unless something else is specified ///////////////////////////////////////////////////////////////////////////JMMH int readIntUsingParsing(istream & in = cin) { int result=0; // result to parse into bool error = false; // assume no errors yet. bool negative = false; // negative numbers bool atLeastOneDigit = false; char buffer[256]; // need to buffer to read in // keep doing it until they enter it right do { // read it in using a whole string error = false; negative = false; atLeastOneDigit = false; result = 0; in.getline(buffer, 256); // now we need to loop through the chars. // STEP 1, ignore any leading space char *currentPos = buffer; // if a space and not end of string, keep going while(*currentPos && (isspace(*currentPos))) currentPos++; // should be at first non-blank character, this could be a + or - if(*currentPos) { // if it's a negative, mark it. if(*currentPos == '-') { negative = true; currentPos++; } // if it's a positive, do likewise else if(*currentPos == '+') { negative = false; currentPos++; } } // otherwise, it must be a digit, if not, it's an error while(*currentPos && (isdigit(*currentPos))) { atLeastOneDigit = true; //multiply by 10 to increment # digits result *= 10; // add the digit to the number (remembering to subtract ASCII base result += *currentPos - '0'; // get next char currentPos++; } // the only thing allowed at the end is space while(*currentPos && (isspace(*currentPos))) currentPos++; // once all is said and done, if we are NOT at the end of the string, we must // have hit a hiccup. if(*currentPos) { cerr << "Sorry, you entered an invalid character \'" << *currentPos << "\' at position " << ((currentPos - buffer)+1) << ". Please try again : "; error = true; } // if we got through, but there was nothing, try agian. else if(!atLeastOneDigit) { cerr << "You must make an entry with at least one digit! Please try again : "; error = true; } // if it failed, the fail flag will get set } while(error); // keep repeating as long as we have errors // now return int, using - if negative to negate the int return (negative) ? (- result) : result; } /////////////////////////////////////////////////////////////////////////////// // main // // This is a driver to test the 3 readInt functions. ///////////////////////////////////////////////////////////////////////////JMMH void main(void) { // char to ask if we should repeat char repeat; int result; // title cout << "Read int test." << endl << endl; cout << "This program tests 3 different ways to read in an int." << endl; do { // read using atoi conversion cout << endl << "Please enter an int [atoi conversion] : "; result = readIntUsingAtoi(); // print back what they gave you cout << "Thank you, I think you entered : " << result << endl; // read using istream error handling cout << endl << "Please enter an int [istream handling] : "; result = readIntUsingIStream(); // print back what they gave you cout << "Thank you, I think you entered : " << result << endl; // read using parsing cout << endl << "Please enter an int [parsing] : "; result = readIntUsingParsing(); // print back what they gave you cout << "Thank you, I think you entered : " << result << endl; // ask if we should do it again cout << endl << "Would you like to try another round? (Y/N) : "; cin >> repeat; // ignore anything after the char, otherwise we will bomb the next read cin.ignore(); } while(toupper(repeat)=='Y'); cout << endl << "Program terminated normally." << endl << endl; }