0

I have a switch in which one case asks the user for several inputs to use for constructing a class object. One of these inputs should be in the form of a number. If a number is not entered it breaks the switch and ends up terminating the program. I want to set up a while(){} condition so that if a non integer is entered it will prompt the user to enter an integer and then continue on with the program.

int main(){
  int in_yob, ranking;
  string in_first_name, in_last_name, in_genre, in_fact, last_name, in_composer;
  char selection, choice;
    do {
      DisplayMenu();
      cin >> selection;
      cout << endl;
      while (!cin || selection < 48 || selection > 53){
        cin.clear();
        cout << "Please make a valid selection" << endl;
        DisplayMenu();
        cin >> selection;
      }
      switch (selection) {
        case 49 : {
            cout << "First Name: ";
            cin >> in_first_name;
            cout << "Last Name: ";
            cin >> in_last_name;
            cout << "Genre: ";
            cin >> in_genre;
            cout << "Year of Birth: ";
            cin >> in_yob;
            cout << "Fact: ";
            cin >> in_fact;
            last_name = in_last_name;
            transform(last_name.begin(), last_name.end(), last_name.begin(), ::tolower);
            Composer& last_name = myDB.AddComposer(in_first_name, in_last_name,
                                                        in_genre, in_yob, in_fact);
            cin.clear();
        }   break;
...
        default: 
            cout << "Please make a valid selection" << endl;
      }
  } while (selection != 48);
}

I have tried inserting a while loop after cin >> in_yob; as:

while(!cin || in_yob > 1){
    cin.clear();
    cout << "Enter a positive enter for year of birth: ";
    cin >> in_yob;
}

but the result is an infinite loop of "Enter a positive enter for year of birth: ". I know this construct for error checking works outside of a switch case so what is the reason that within a switch case i'm getting this result? Also how would you go about fixing this so that I can check for and prevent an input error? Thanks.

Grr
  • 15,553
  • 7
  • 65
  • 85
  • What is `selection`? What type is it? And why compare with magic numbers instead of using e.g. [`std::isdigit`](http://en.cppreference.com/w/cpp/string/byte/isdigit) to make sure you have a digit? Or the very least use proper character literals like e.g. `'0'` instead of the cryptic `48`. – Some programmer dude Jul 15 '15 at 15:43
  • Entering a negative number will give you some clues. – Captain Obvlious Jul 15 '15 at 15:44
  • @JoachimPileborg selection is a `char` and the number isn't magic. its the char code for the users menu selection. – Grr Jul 15 '15 at 17:00
  • A "magic number" is an ["Unnamed numerical constant"](https://en.wikipedia.org/wiki/Magic_number_%28programming%29#Unnamed_numerical_constants), and for readers of your code is just a number without any special meaning. A character literal `'0'` have a meaning, gives some context, and is always portable no matter the character encoding, the "magic number" `48` could mean anything, and will not work with encoding that do not derive from ASCII. – Some programmer dude Jul 15 '15 at 17:05
  • Also, since `selection` is a character your input validation function will not work as expected, the second input operation will read the newline you entered for the first input operation. – Some programmer dude Jul 15 '15 at 17:07
  • I'm not sure I follow @JoachimPileborg. Are you saying the input for `in_yob` will read the newline entered for `selection` or that it will read the line entered for `in_genre`? – Grr Jul 15 '15 at 17:53

2 Answers2

1

[To explain my self with more space and better formatting better than in a comment I post this as an answer instead as of a comment.]

When you enter input, like for example

1

the input buffer actually contains two characters, firs the digit '1' and then the newline '\n'.

When you read a single character, the input operation extracts the first character, the digit, and writes it to your variable.

If you then read another character, it will read the newline, and not whatever comes after.

There is a trick to "ignore" characters until, for example, a newline, and that is done by using the std::istream::ignore, and if you follow the link to the reference you will see a very good example on how to ignore anything up to and including the newline.

So in your case it's not enough to just call clear you need to call ignore as well in your input validation loop. And if you continue to read single characters, you need to call ignore before that as well.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Oh now i see what you meant. I'm still learning this but that is quite obvious and i feel dumb. How else could the following input request post on a newline save having a newline after the input character. Thank you. – Grr Jul 15 '15 at 18:16
0

You needed to clear the input stream.

#include <iostream>
#include <string>
int in_yob = 0;
int main()
{
    while(std::cin.good() && in_yob < 1){
        std::cin.clear();
        std::cout << "Enter a positive enter for year of birth: ";
        if( !(std::cin >> in_yob) ) {
            std::cin.clear();
            std::cin.ignore(10000,'\n');
        }
    }
    std::cout << "YOB " << in_yob << std::endl;

}
Robert Jacobs
  • 3,266
  • 1
  • 20
  • 30
  • I tried this. Same result, infinite loop of "Enter a positive integer for year of birth: " – Grr Jul 15 '15 at 17:01
  • Code changed. Now works. Might as well be explicit that you want cin to be good. Also you want to check for in_yob to be invalid. – Robert Jacobs Jul 15 '15 at 17:12
  • Now it just runs the cout for the remainder of the switch case taking no inputs, pulls up the menu and then runs the default case error. – Grr Jul 15 '15 at 17:52
  • if you run it inside of a switch as above it doesn't. That's why I'm confused as your code indeed works outside of a switch. See [c++ shell example](http://cpp.sh/2dgb) – Grr Jul 15 '15 at 18:07
  • Cleared the input stream on error. See http://stackoverflow.com/questions/5131647/why-would-we-call-cin-clear-and-cin-ignore-after-reading-input – Robert Jacobs Jul 15 '15 at 19:28