0

I am kind of beginner in C++ and I want a simple way to convert a char string (char * str1) to an integer. I am able to do that with atoi, but I have read that this function is "devil" and should not be used. I don't want to use C++ std:string for many reasons, so my string must be in char* format. Do you have any suggestions?

Thanks in advance

Tahseen
  • 9
  • 2
  • 2
    Claiming that [`atoi`](https://en.cppreference.com/w/cpp/string/byte/atoi) is "[the] devil" might be a little to strong. It doesn't have very much error checking or validation, if that's what you want. Then you could use [`std::stoi`](http://en.cppreference.com/w/cpp/string/basic_string/stol) instead. – Some programmer dude Nov 19 '18 at 09:16
  • 4
    On an unrelated note: "I don't want to use C++ std:string for many reasons" you say, and I'll wager that most if not all of them are bad or wrong. – Some programmer dude Nov 19 '18 at 09:23
  • [`strtol()`](https://en.cppreference.com/w/cpp/string/byte/strtol) is another option with more error-checking options. However I'd recommend you to use `std::string` and [`std::stoi`](https://en.cppreference.com/w/cpp/string/basic_string/stol) – Yksisarvinen Nov 19 '18 at 09:24

4 Answers4

2

As an alternative, still C-style, use sscanf:

/* sscanf example */
#include <stdio.h>

int main ()
{
  char sentence []="Rudolph is 12 years old";
  char str [20];
  int i;

  sscanf (sentence,"%s %*s %d",str,&i);
  printf ("%s -> %d\n",str,i);

  return 0;
}

[EDIT] As reported by @Killzone Kid in the comment, there is an std version.

#include <iostream>
#include <clocale>
#include <cstdio>

int main()
{
    int i, j;
    float x, y;
    char str1[10], str2[4];
    wchar_t warr[2];
    std::setlocale(LC_ALL, "en_US.utf8");

    char input[] = u8"25 54.32E-1 Thompson 56789 0123 56ß水";
    // parse as follows:
    // %d: an integer 
    // %f: a floating-point value
    // %9s: a string of at most 9 non-whitespace characters
    // %2d: two-digit integer (digits 5 and 6)
    // %f: a floating-point value (digits 7, 8, 9)
    // %*d an integer which isn't stored anywhere
    // ' ': all consecutive whitespace
    // %3[0-9]: a string of at most 3 digits (digits 5 and 6)
    // %2lc: two wide characters, using multibyte to wide conversion
    int ret = std::sscanf(input, "%d%f%9s%2d%f%*d %3[0-9]%2lc",
                     &i, &x, str1, &j, &y, str2, warr);

    std::cout << "Converted " << ret << " fields:\n"
              << "i = " << i << "\nx = " << x << '\n'
              << "str1 = " << str1 << "\nj = " << j << '\n'
              << "y = " << y << "\nstr2 = " << str2 << '\n'
              << std::hex << "warr[0] = U+" << warr[0]
              << " warr[1] = U+" << warr[1] << '\n';
}
Tu.Ma.
  • 1,325
  • 10
  • 27
  • 1
    There is std:: version https://en.cppreference.com/w/cpp/io/c/fscanf – Killzone Kid Nov 19 '18 at 10:02
  • Thanks, I did not know it. I added it to the answer. – Tu.Ma. Nov 19 '18 at 10:07
  • I don't know if replacing atoi with sscanf is such an improvement. Although quite versatile, it does carry it's own bag of gotchas. – rioki Nov 19 '18 at 10:09
  • I totally agree. The question is not really clear on the reasons behind the choice of using C-style strings, or not using atoi. So I just suggested an alternative, as requested. – Tu.Ma. Nov 19 '18 at 10:10
1

You should use C++ stoi (https://en.cppreference.com/w/cpp/string/basic_string/stol):

int main()
{
    std::cout << std::stoi("123");
}

Of course, you should pass a pos argument to see if the string was converted entirely or not.

Matthieu Brucher
  • 21,634
  • 7
  • 38
  • 62
0

C++ style, but without string:

#include <iostream>
#include <sstream>

int str2i(const char *str)
{
    std::stringstream ss;
    ss << str;
    int i;
    ss >> i;
    return i;
}

int main()
{
    std::cout << str2i("123");
}
snake_style
  • 1,139
  • 7
  • 16
0

You need to consider the reason why atoi is considered unsafe. There is no way to know if the conversion worked.

A similar C function function is strol. To use it you would do the following:

char* input_string = ...
char* end = nullptr;
long value = strol(input_string, &end, 10);
if (input_string == end) {
   // converison failed
}

Alternatively, if you are programing C++ and not C, you can use one of my generic read functions:

template <typename T>
T from_string(const std::string_view str)
{
    std::stringstream buff(str);
    T value;
    buff >> value;

    // check if all input was consumed
    if (buff.gcount() != str.size())
    {
        throw std::runtime_exception("Failed to parse string.");
    }

    return value;
}    

This can then be used on anything that has a stream in operator. In your case:

 const char* int_string = "1337";
 int int_value = from_string<int>(int_string );
rioki
  • 5,988
  • 5
  • 32
  • 55