0

I am trying to make a completely error-proof input for switch cases. It needs to not fail if the user puts in the wrong number, a letter, or a long string of numbers or letters (This is where I have had errors before).

To prevent an error if the user inputs eg. "asdghdk3" I have tried using an array so it will check each letter until it finds a number.

I have then tried to turn it into an integer for the switch case. Sadly my code will not work. Does anyone have any suggestions or improvements? Thank you.

#include <iostream>
#include <vector>
#include <cmath>
#include <cstdlib>

using namespace std;

int main()
{
    cout<<"Please choose the method you would like to use to evaluate the potential. Please enter 1,2 or 3:"<<endl;
    cout<<"1. my method. \n2. jacobi method. \n3. Exit programme. \nYou chose: ";

    char choice[20];
    bool k = true;

    int choice2;
    while (k == true){
        fgets(choice, sizeof choice, stdin);
        for(int j=0; j<sizeof(choice); j++){
            if (isdigit(choice[j])==true){  //I want it to check every character until it finds a number.
                choice2 = atoi(choice[j]); //changed name as now integer to be used in switch case.
                k = false;
                break; //so that it breaks out of the for loops because it has found a number
            }
            else{
                continue;
            }
        }
        cout<<"Incorrect input please try again";
    }

    cout<<"\nchoice2= "<<choice2<<endl;

    switch ( choice2 ) {
        case 1 :
            // Code
            break;
        case 2:
            // Code
            break;
        case 3:
            //code to exit programme
            break;
        default:
            // Code
            break;
    }

    return 0;
}

EDIT: I would like it to only accept 1, 2 or 3 and for everything else return incorrect input please try again.

using namespace std;

int main()
{
    string line;
    getline(cin, line);
    istringstream choice(line);
    int number;
    choice >> number;

    if (choice)
    {
        if (choice == 1)
        {
            cout << "you chose option 1\n";
            //code.....
        }
        else if (choice == 2)
        {
            cout<< "you chose option 2\n";
            //code.....
        }
        else if (choice == 3)
        {
            cout<< "you chose option 3\n";
            //code......
        }
    }
    else
    {
        cout << "input does not start with a number or is too big for an int\n";
    }
return 0;
}
user3343772
  • 5
  • 1
  • 4
  • Sorry I forgot to add that this doesn't work because now choice is not actually I number, I think. To fix this I tried changing choice to number in the if statements. – user3343772 Feb 23 '14 at 18:09
  • In your edited code, you compare the stream itself with 1, 2 and 3, not the number which was entered! This is wrong. Just do it exactly as in the example in my answer, then in the innermost part (where the string stream was already checked against eof and "input ok" is printed), compare the number variable with 1, 2 or 3. – Christian Hackl Feb 23 '14 at 18:47
  • Hi Christian, Thanks this now works, almost! I have changed it so one of the options is zero. The only problem is if a 0 is entered then it returns the "input does not start with a number..." Is zero treated differently to a normal number in strings? How can I fix this? Thanks. – user3343772 Feb 24 '14 at 10:40

2 Answers2

0

You should be using std::cin and checking its status:

int choice = -1;
if (cin >> choice)
{
    // you know user entered a number, check that it's in the correct range

    if (cin.peek() != '\n')
        // there's more input, so probably an error
}
else
{
    // bad input
}
Eugene S
  • 3,092
  • 18
  • 34
  • Thanks, but what if they have entered a several letters? This will still break it. – user3343772 Feb 23 '14 at 17:06
  • give me an example input that you think will break it – Eugene S Feb 23 '14 at 17:08
  • Something like "ajshdkajshds7" – user3343772 Feb 23 '14 at 17:09
  • Nope, you're wrong, because `cin` will be in a failed state if it tries to read a numeric type and encounters a non-number. http://ideone.com/Ku9fy0 and – Eugene S Feb 23 '14 at 17:17
  • 1
    @unluddite: This will not work if the user enters e.g. "123a", because the stream will be quite happy with extracting just "123" from it and completely ignore the fact that the user also entered an "a" at the end (which was probably an error). – Christian Hackl Feb 23 '14 at 17:34
0

Read a whole line from std::cin into a std::string with std::getline, then convert the line to an integer number with a std::istringstream. Finally, after the conversion, check if there are characters left in the string stream. Here's a complete example:

#include <iostream>
#include <sstream>
#include <string>

int main()
{
    std::string line;
    std::getline(std::cin, line);
    std::istringstream is(line);
    int number;
    is >> number;

    if (is)
    {
        if (!is.eof())
        {
            std::cerr << "input does not end with a number\n";
        }
        else
        {
            std::cout << "input ok\n";
        }
    }
    else
    {
        std::cerr << "inut does not start with a number or is too big for an int\n";
    }
}
Christian Hackl
  • 27,051
  • 3
  • 32
  • 62
  • Thank you this helps. I have tried playing around with it to match it to what I need but I have a few questions. Does the is.eof() 'attach' is to eof()? I've not tried using that before. And what is the difference between a string and a stringstream? – user3343772 Feb 23 '14 at 17:47
  • eof() is a member function. There is no "attaching" involved, but actually I'm not sure what exactly you mean. – Christian Hackl Feb 23 '14 at 17:48
  • And a string stream is a special kind of stream which operates on strings inside of your program. – Christian Hackl Feb 23 '14 at 17:49
  • Sorry, excuse the first bit of that question I've looked up some information on member functions now. In you bit of code you check whether the last part of the input is a number which isn't exactly what I'm trying to do. Could you please look at the edit I've put above where I've tried changing you code. Thank you! – user3343772 Feb 23 '14 at 18:06
  • The I/O streams library of C++ is a particularly bad way to learn about classes and member functions, because due to historical reasons it is so overly complicated and full of bad names and hard-to-use interfaces. At any rate, your edit IMO shows that you did not completely understand the example I gave. Just put your switch into the else block where eof has been checked (i.e. where it says "input ok"), then you'll be fine. – Christian Hackl Feb 23 '14 at 18:52
  • You left off a critical piece: `is >> number >> std::ws`. Now you can know you got a number properly `if (is && is.eof())`. Everything else is failure. – Dúthomhas Sep 05 '17 at 07:09