-1

I'm new to statically typed C++. In JavaScript, I could just check the data type first, but that seems to be very complicated, and the answers all seem to imply that you aren't "getting" the language.

here's the code I was testing out rand() with, where I came upon the issue of converting strings to integers:

int main(){
std::string input;
    cout <<endl<< "What to do?"<<endl;
    cin >> input;
    if (input == "rand")
    {
        cout << "what is the max?" << endl;
        cin >> input;
        int number;
        if (stoi(input) > 1) {
            number = stoi(input);
        }
        else {
            number = 10;
            cout << "using 10"<<endl;
        }
        cout << rand() % stoi(input);
        return main();
    }
}

so in Javascript, I would just check the type of input or result, but what do people do in C++?

Not allowed to say thank you in the comments so I'm saying thank you here!

sheepdeets
  • 39
  • 4
  • Don't check the type of the input (it will be a string anyway), check if it's value can be casted to a valid integer by `stoi`. Solutions to this are proposed [here](https://stackoverflow.com/questions/4654636/how-to-determine-if-a-string-is-a-number-with-c). – sevsev Aug 10 '20 at 11:19
  • The question is not about `std::atoi` (which does not perform any checking), but about `std::stoi` (and in extension `std::strtoi`). – gha.st Aug 10 '20 at 11:20
  • 1
    In part the issue is what do you consider to be a valid number? `stoi` has it's own definition and as already stated it throws an exception if that isn't met. If `stoi` doesn't do what you want then just perform you own tests on `input`, use a regex perhaps. – john Aug 10 '20 at 11:22
  • In two spots you set `number`, but it is never used. Probably should only call `stoi(input)` once, and use that to set `number`, and then use number after that spot in the code. – Eljay Aug 10 '20 at 11:24

2 Answers2

6

Well, let's try out what happens: https://godbolt.org/z/1zahbW

As you can see, std::stoi throws an exception if you pass it invalid input or its input is out of range.

You should, however, be aware that std::cin >> some_string; is somewhat non-obvious in that it reads in the first "word", not a line or anything like that, and that std::stoi does the same thing (again).

One way to perform the check, could be like this:

#include <string>
#include <iostream>

int main(){
    std::cout << "Please give me a number: " << std::flush;

    std::string input;
    std::getline(std::cin, input);
    try {
        auto value = std::stoi(input);
        std::cout << "Thanks for the " << value << " (but the string was \"" << input << "\")\n";
    } catch(std::invalid_argument const&) {
        std::cout << "The provided value is not an integer\n";
    } catch(std::out_of_range const&) {
        std::cout << "The provided value is out of range\n";
    }
}

https://godbolt.org/z/rKrv8G

Note that this will parse " 42 xyz" as 42. If that is a problem for your use case, you may wish to use std::strtoi directly, or to check if your input is valid before parsing (e.g., using a regex)

gha.st
  • 10,236
  • 1
  • 33
  • 57
2

Regarding to the documentation of std::stoi it throws an std::invalid_argument.

What you could do is to place your std::stoi call inside a try and then catch the std::invalid_argument, but personally i wouldn't do that.

Instead, it is (most likely) a lot better to check if the first character of your input is an int, because if it is one, it can simply be parsed by std::stoi.

You can do that by e.g. doing the following:

int max = 0;
std::string input;
std::cin >> input;

if(std::isdigit(input[0]))
  max = std::stoi(input);

EDIT: Please note that this would not respect the case of a too big number, to handle that case you would need an additional check.

Amachi
  • 102
  • 11
  • 1
    This may still throw an exception if your input is larger than the maximum integer value. It will also pass values such as "42chickens". – gha.st Aug 10 '20 at 11:29
  • @gha.st yes, fair point with the integer overflow, you could add an extra check for that. For the case with '42chicken' i would actually want to parse the 42 out of there as it is up to the user to input the correct number (as it is requested). so those attempts are usually tests to try and get a program to misbehave, which wouldn't be the case here. – Amachi Aug 10 '20 at 11:31
  • This answer is the easiest for me to understand, and I wasn't aware of isdigit, which seems intuitive to me. I can imagine making a simple function to check if the input is fully a number or contains non-number characters. – sheepdeets Aug 10 '20 at 12:07
  • 1
    @sheepdeets please be aware that as gha.st mentioned, this is not handling the case of a potential integer overflow. you'd need an additional check for it. – Amachi Aug 10 '20 at 12:09