9

I am really confused. I have to be missing something rather simple but nothing I am reading about strtol() is making sense. Can someone spell it out for me in a really basic way, as well as give an example for how I might get something like the following to work?

string input = getUserInput;
int numberinput = strtol(input,?,?);
James Thompson
  • 245
  • 1
  • 6
  • 13

4 Answers4

33

The first argument is the string. It has to be passed in as a C string, so if you have a std::string use .c_str() first.

The second argument is optional, and specifies a char * to store a pointer to the character after the end of the number. This is useful when converting a string containing several integers, but if you don't need it, just set this argument to NULL.

The third argument is the radix (base) to convert. strtol can do anything from binary (base 2) to base 36. If you want strtol to pick the base automatically based on prefix, pass in 0.

So, the simplest usage would be

long l = strtol(input.c_str(), NULL, 0);

If you know you are getting decimal numbers:

long l = strtol(input.c_str(), NULL, 10);

strtol returns 0 if there are no convertible characters at the start of the string. If you want to check if strtol succeeded, use the middle argument:

const char *s = input.c_str();
char *t;
long l = strtol(s, &t, 10);
if(s == t) {
    /* strtol failed */
}

If you're using C++11, use stol instead:

long l = stol(input);

Alternately, you can just use a stringstream, which has the advantage of being able to read many items with ease just like cin:

stringstream ss(input);
long l;
ss >> l;
nneonneo
  • 171,345
  • 36
  • 312
  • 383
  • Ok so this got my code to work. Just to check passing a string with no number in it would yield what exactly? Also what is the difference between a string and a C string? – James Thompson Feb 10 '13 at 02:50
  • If you don't have a number in the string, `strtol` returns 0. Since that's a legal return value, you have to use the middle parameter to disambiguate. – nneonneo Feb 10 '13 at 02:51
  • 1
    @JamesThompson: A `string` (`std::string`) is a C++ object that represents a string. It is the preferred way to handle strings in C++. A C string is a sequence of characters which ends in a null terminator (`\0`) and is represented by a pointer to the first character in the sequence (a `char *`). C functions (like `strtol`) don't take `string` objects, so you have to pass a C string instead. – nneonneo Feb 10 '13 at 02:55
  • oh no that's a problem then. I need to be able to catch when a number is not entered, however for my project 0 is a valid number so I can't just do a if(int = 0) – James Thompson Feb 10 '13 at 02:56
  • Ok so it works, and I thank you. But I don't actually get it. Probably because Im not use to pointers. What is actually being compared in the statement (s==t) – James Thompson Feb 10 '13 at 03:12
  • 1
    `strtol` saves a pointer to the first non-numeric character in `t`. If `s==t`, then it means the first character in the string is non-numeric, i.e. the string doesn't start with a number. – nneonneo Feb 10 '13 at 03:14
  • Ok that make sense. One last question. I actually have to do the same thing with doubles I know there is a strtod by using the same code isn't working does strtod use diff params? or what am i missing – James Thompson Feb 10 '13 at 03:23
  • Google for the function. Does it have different parameters? – nneonneo Feb 10 '13 at 03:24
4

Suppose you're given a string char const * str. Now convert it like this:

#include <cstdlib>
#include <cerrno>

char * e;
errno = 0;

long n = std::strtol(str, &e, 0);

The last argument 0 determines the number base you want to apply; 0 means "auto-detect". Other sensible values are 8, 10 or 16.

Next you need to inspect the end pointer e. This points to the character after the consumed input. Thus if all input was consumed, it points to the null-terminator.

if (*e != '\0') { /* error, die */ }

It's also possible to allow for partial input consumption using e, but that's the sort of stuff that you'll understand when you actually need it.

Lastly, you should check for errors, which can essentially only be overflow errors if the input doesn't fit into the destination type:

if (errno != 0) { /* error, die */ }

In C++, it might be preferable to use std::stol, though you don't get to pick the number base in this case:

#include <string>

try { long n = std::stol(str); }
catch (std::invalid_argument const & e) { /* error */ }
catch (std::out_of_range const & e)     { /* error */ }
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
0

Quote from C++ reference:

long int strtol ( const char * str, char ** endptr, int base );

Convert string to long integer

Parses the C string str interpreting its content as an integral number of the specified base, which is returned as a long int value. If endptr is not a null pointer, the function also sets the value of endptr to point to the first character after the number.

So try something like

long l = strtol(pointerToStartOfString, NULL, 0)
Bernhard Barker
  • 54,589
  • 14
  • 104
  • 138
Patashu
  • 21,443
  • 3
  • 45
  • 53
  • Im new to C++ so im not use to pointers although i aware of the concept. How to i find pointerToStartOfString for my string and what should it look like – James Thompson Feb 10 '13 at 02:45
  • How it works in C is like this: `char` is a variable containing a character. `char*` is a variable containing a pointer. The pointer, when dereferenced, points to a character (usually the start of many characters in memory, called a 'string'). So if you have `char* MyPointer`, then you can do `strtol(MyPointer, NULL, 0)`. – Patashu Feb 10 '13 at 02:49
0

I always use simply strol(str,0,0) - it returns long value. 0 for radix (last parameter) means to auto-detect it from input string, so both 0x10 as hex and 10 as decimal could be used in input string.

mvp
  • 111,019
  • 13
  • 122
  • 148
  • Trying to use strol(input,0,0) gave me the error of "cannot convert `std::string' to `const char*' for argument `1' to `long int strtol(const char*, char**, int)'" – James Thompson Feb 10 '13 at 02:42
  • Yes, C++ has `std::string` which is not `char*`. Even though they're used for the same thing (holding strings) functions that work on one do not work on the other. – Patashu Feb 10 '13 at 02:50
  • for std::string use `strtol(str.c_str(),0,0)` – mvp Feb 10 '13 at 03:24
  • True about `0` leads to auto-detect the base. With "0109" the result is `8` as 8 is the auto-detected base. – chux - Reinstate Monica Oct 23 '14 at 21:12