Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

Given a string that should represent a number, I'd like to put it into a conversion function which would provide notification if the whole string did not convert.

For input: "12":

  • istringstream::operator>> outputs 12
  • atoi outputs 12
  • stoi outputs 12

For input "1X" I'd like a failure response but I get:

  • istringstream::operator>> outputs 1
  • atoi outputs 1
  • stoi outputs 1

For input "X2":

  • istringstream::operator>> outputs 0 and sets an error flag
  • atoi outputs 0
  • stoi throws an error

[Live Example]

Is there a way to provoke the error behavior on input "1X"?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
117 views
Welcome To Ask or Share your Answers For Others

1 Answer

Edit: In or later from_chars is preferred. See here for more: https://topanswers.xyz/cplusplus?q=724#a839


For a given string str there are several ways to accomplish this each with advantages and disadvantages. I've written a live example here: https://ideone.com/LO2Qnq and discuss each below:

strtol

As suggested here strtol's out-parameter can be used to get the number of characters read. strtol actually returns a long not an int so a cast is happening on the return.

char* size;
const int num = strtol(str.c_str(), &size, 10);

if(distance(str.c_str(), const_cast<const char*>(size)) == str.size()) {
    cout << "strtol: " << num << endl;
} else {
    cout << "strtol: error
";
}

Note that this uses str.c_str() to refer to the same string. c_str Returns pointer to the underlying array serving as character storage not a temporary if you have C++11:

c_str() and data() perform the same function

Also note that the pointer returned by c_str will be valid between the strtol and distance calls unless:

  • Passing a non-const reference to the string to any standard library function
  • Calling non-const member functions on the string, excluding operator[], at(), front(), back(), begin(), rbegin(), end() and rend()

If you violate either of these cases you'll need to make a temporary copy of i's underlying const char* and perform the test on that.

sscanf

sscanf can use %zn to return the number of characters read which may be more intuitive than doing a pointer comparison. If base is important, sscanf may not be a good choice. Unlike strtol and stoi which support bases 2 - 36, sscanf provides specifiers for only octal (%o), decimal (%d), and hexadecimal (%x).

size_t size;
int num;

if(sscanf(str.c_str(), "%d%zn", &num, &size) == 1 && size == str.size()) {
    cout << "sscanf: " << num << endl;
} else {
    cout << "sscanf: error
";
}

stoi

As suggested here stoi's output parameter works like sscanf's %n returning the number of characters read. In keeping with C++ this takes a string and unlike the C implementations above stoi throws an invalid_argument if the first non-whitespace character is not considered a digit for the current base, and this unfortunately means that unlike the C implementations this must check for an error in both the try and catch blocks.

try {
    size_t size;
    const auto num = stoi(str, &size);

    if(size == str.size()) {
        cout << "stoi: " << num << endl;
    } else {
        throw invalid_argument("invalid stoi argument");
    }
} catch(const invalid_argument& /*e*/) {
    cout << "stoi: error
";
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...