2

I am trying to allow only integrers to be inputted

Should Reject:

  • 5h
  • 3.4
  • 3.gh
  • 3.0
  • htr

Should Accept:

  • -5
  • 0
  • 78

Current Code

int getIntInput() {
    int userInput;

    while (true) {
        std::cout << "> ";
        std::cin >> userInput;
        std::cout << std::flush;

        if (std::cin.fail()) {
            std::string cinBuffer;
            std::cin.clear();
            std::getline(std::cin, cinBuffer);
            continue;
        }
        break;
    }
    return userInput;
}

Updated Code

Issues:

  • Accepts all rejections excluding "htr" (No numerals)

    int getIntInput() {
            std::string rawInput;
            int parsedinput;
    
            while (true) {
                std::cout << "> ";
                std::getline(std::cin, rawInput);
                std::cout << std::flush;
    
                try {
                    parsedinput = std::stoi(rawInput);
    
                } catch (std::invalid_argument & e) {
                    continue;
    
                } catch (std::out_of_range & e) {
                    continue;
                }
    
               break;
        }
        return parsedinput;
    }
    

Finished Code

  • Accepts only integers with an optional parameter which will allow negative numbers to be accepted or rejected.

    int getIntInput(bool allowNegatives = true) {
        bool validIntInput;
        std::string rawInput;
        int parsedinput;
    
        while (true) {
            validIntInput = true;
    
            // Grabs the entire input line
            std::cout << "> ";
            std::getline(std::cin, rawInput);
            std::cout << std::flush;
    
            for (int i = 0; i < rawInput.length(); i++) {
                // Checks to see if all digits are a number as well as to see if the number is a negative number
                if (!isdigit(rawInput[i]) && !(allowNegatives && i == 0 && rawInput[i] == '-')) {
                    validIntInput = false;
                    break;
                }
            }
    
            if (!validIntInput) {
                continue;
    
            } else {
                try {
                    // Try parse the string to an int
                    parsedinput = std::stoi(rawInput);
    
                    // Catch all possible exceptions, another input will be required
                } catch (...) {
                    continue;
                }
                // If the code reaches here then the string has been parsed to an int
                break;
            }
        }
        return  parsedinput;}
    
2
  • 1
    What are your requirements? I have no idea what do you expect should happen. It would be best if you provide couple examples of user input and expected result. Commented Jun 16, 2018 at 16:18
  • Get only intergers as an input, if a value such as 4.5 is entered then the value should not be accepted and another input should be entered Commented Jun 16, 2018 at 17:14

3 Answers 3

2

The way cin works when having to read an int, is that it starts parsing the integer and stops when it finds a non-int character, storing the parsed int in the variable. That's why on float numbers it stops on the dot and in input '5g' it will stop on g.

What you can do instead if you only want integer input, is to read the whole line and then check if every character in your string is numeric, with the following piece of code:

bool onlyNums = true;
for (int i=0;i<rawInput.size();i++) {
    if (!isdigit(rawInput[i]))
        onlyNums = false;
}

if (!onlyNums)
    continue;

(You have to include ctype.h library for the above code)

Sign up to request clarification or add additional context in comments.

5 Comments

So for future use, should I always use getline?
Depends on what you need pretty much, cin is powerful for reading tokens that are expected to have a specific format, but since you need to verify the whole input line in this example it's better to read the whole line and process it after.
Could you please look at my updated answer? Still having issues.
Yes, my bad, didn't test the implementation I proposed you. Edited my response, should be ok now. All parsing functions would have to go through the whole string anyways to check if every character is numeric.
So I have built upon your two answers, is what I've done overkill or is it acceptable?
2

If you don't mind the overhead, I would grab the input from cin with cin.getline() and save it into a string. Then loop through the string and call isdigit on each char. You can discard the chars that aren't digits by useing the str.erase function.

You will need to #include cctype for isdigit().

Note: this will have at least O(N) runtime based on the length of your string.

Comments

0
template<class T>
T findInStreamLineWith(std::istream &input) {
    std::string line;
    while (std::getline(input, line)) {
        std::istringstream stream(line);
        T x;
        if (stream >> x >> std::ws && stream.eof()) {
            return x;
        }
        // reenter value
        // cout << "Enter value again: ";
    }
    throw std::invalid_argument("can't find value in stream");
}

…
auto x = findInStreamLineWith<int>(std::cin);

2 Comments

I get 9 errors on VS2017, some text or comments would be appreciated as I am still a beginner with C++.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.