-1

I started a course in C today and I am not really sure how you would use the strtol function to convert a string of an integer from command line arguments instead of using the atoi function (for some reason, I am not allowed to use the atoi function.

How would I change the following code to use the strtol function instead? If possible, please explain what the variables you create (if any) do with relevance to the strtol function.

int main( int argc, char * argv[] ) {
    int num1 = atoi(argv[1]);
    int num2 = atoi(argv[2]);
    
    printf("num1 = %d, num2 = %d", num1, num2);
    return 0;
}
A P Jo
  • 446
  • 1
  • 4
  • 15
neRienn
  • 41
  • 3
  • 1
    Does this answer your question? [Correct usage of strtol](https://stackoverflow.com/questions/14176123/correct-usage-of-strtol) – Louis Go Aug 20 '20 at 02:31
  • 1
    Or [this](https://en.cppreference.com/w/c/string/byte/strtol) – paddy Aug 20 '20 at 02:39
  • 2
    All questions can "simply the Googled" for answers. In fact Stack Overflow is the top supplier of answers. In Google Search. But I believe SO is not a home for an elite of questions and answers. As stated in [https://stackoverflow.com/help/dont-ask] this question seems to be well formulated, @JakeFry – arfneto Aug 20 '20 at 02:40
  • 1
    see the reason [why atoi() shouldn't be used](https://stackoverflow.com/q/17710018/995714). And to know how to use `strtol` why don't read [its documentation](https://en.cppreference.com/w/c/string/byte/strtol)? – phuclv Aug 20 '20 at 03:05
  • @arfneto IMO, his question is mostly answered by knowing how `strtol()` works, which can be Googled, looked up in a book -- it is a bit like asking what the `;` or `>>` does. I agree wholeheartedly that S.O is **not** for elitism, but request you to see my POV. From what I see, his question is solved by looking up the prototype (which is also how you have answered, except you went on to directly give him the exact code too). If my view is somehow incorrect, correct me. Further, i recommend, for the near future , to not use `]` after a link such that the link is rendered invalid. – A P Jo Aug 20 '20 at 05:20
  • Writing a simple `atoi` equivalent is a very simple exercise..... You'll use `isdigit` to test if the current character is a digit, and you iterate. – Basile Starynkevitch Aug 20 '20 at 16:10

2 Answers2

2

convert a number from the command line to an integer using strtol

[Found many strtol() posts, yet not a direct good C answer to OP's question on SO.]

Good strtol() usage involves base, errno and the end pointer and testing for various outcomes.

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

int main(int argc, char *argv[]) {
  for (int a = 1; a < argc; a++) { // check command line arguments after argv[0].
    int base = 10; // convert strings as encoded with decimal digits.
    char *endptr; // location to store the end of conversion.
    errno = 0;
    long val = strtol(argv[a], &endptr, base);
    if (argv[a] == endptr) {
      printf("No conversion.\n");
    } else if (errno == ERANGE) { // ***
      printf("Out of `long` range.\n");
    } else if (errno) {
      printf("Implementation specific error %d detected.\n", errno);
    } else if (*endptr) {
      printf("Trailing junk <%s> after the numeric part.\n", endptr);
    } else {
      printf("Success.\n");
    }
    printf("<%s> --> %ld:", argv[a], val);
  }
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • You might want to add the include files. – chqrlie Aug 20 '20 at 14:46
  • *Better code uses the value of `errno` promptly after `strtol()`* Indeed. And note that your call to `printf()` [is allowed to change the value of `errno`](https://port70.net/~nsz/c/c11/n1570.html#7.5p3): "The value of errno may be set to nonzero by a library function call whether or not there is an error, provided the use of errno is not documented in the description of the function in this International Standard." And [`printf()`](https://port70.net/~nsz/c/c11/n1570.html#7.21.6.3) is not documented to set `errno`. – Andrew Henle May 04 '23 at 12:55
  • 1
    @AndrewHenle Comment replaced with shift in print to address that issue. – chux - Reinstate Monica May 04 '23 at 14:27
0

the prototype as you may know is

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

where str is the original string and endptr is the address of a pointer to the rest of the string after a number is found. base is, well, the base. strtol() returns 0 when it finds no number. Sure it returns 0 when it finds a 0 and then you must check the remaining data and eventually start over again.

This

Original string: "2001 2002 2003 2004 0 2005"

    2001 parsed string now: " 2002 2003 2004 0 2005"
    2002 parsed string now: " 2003 2004 0 2005"
    2003 parsed string now: " 2004 0 2005"
    2004 parsed string now: " 0 2005"

0 was parsed: may be just the end of input

5 bytes remaining at the string: " 2005"

is the output of the short program below and may help you understand the mechanic

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char* argv[])
{
    const char* pattern =
        "2001 2002 2003 2004 0 2005";
    char* input = (char*)pattern;
    char* after = NULL;
    long long int num1 = strtol(input, &after, 10);
    printf("Original string: \"%s\"\n\n", pattern);
    do
    {   
        printf("%8lld parsed\tstring now: \"%s\"\n", num1, after);
        input = after;
        num1 = strtol(input, &after, 10);
    } while (num1 != 0);
    printf("\n0 was parsed: may be just the end of input\n");
    printf("\n%ud bytes remaining at the string: \"%s\"\n",
        strlen(after), after);
    return 0;
};

// Compiled under MSVC 19.27
arfneto
  • 1,227
  • 1
  • 6
  • 13
  • why was this answer downvoted ? It is a valid answer. – A P Jo Aug 20 '20 at 05:21
  • arfneto, Why use `"%d"` with `long`? Recommend to enable more warnings too. – chux - Reinstate Monica Aug 20 '20 at 05:28
  • @chux-ReinstateMonica has a point. Use `%lld` and `long long` instead, since `long` means different things on different platforms/compilers - most notably MSVC interprets `long` as the same size as a plain `int` and Clang/GCC interpret `long` akin to a `long long`. – A P Jo Aug 20 '20 at 09:49
  • 1
    @APJo as `strtol()` returns a `long`. Using a `long long num1` is possible, yet simply using a `long num1`, as OP has, does match `strtol()`. Could use `strtoll()` to go with `long long`. IAC, the type of `num1`, `strto...()`, and print specifier deserve to be coordinated. – chux - Reinstate Monica Aug 20 '20 at 10:04
  • 1
    Recommend `%zu` with `strlen()` rather than `%d` to avoid UB. – chux - Reinstate Monica Aug 20 '20 at 10:44
  • You should also document the different bases available, especially the value `0` for `base`, the behavior on numbers outside the range of `long` and the test for no conversion is `after == input`. – chqrlie Aug 20 '20 at 14:46
  • I saw no reason to do that, as I saw no point in treating `errno` and possible conditions on 3 compilers etc. See the title of the question and the description from the author. But I understand your point @chqrlie and others. – arfneto Aug 20 '20 at 15:28
  • OK. I looked like you were writing a complete course on `strlen()`. Still the test for `0` return value is a bit misleading, the comparison `after == input` is a much better way to test for invalid input. – chqrlie Aug 20 '20 at 15:32
  • That was on purpose. I put an actual "0" on the string just to alert a beginner of the fact that `strtol()` return 0 when there no number and for sure when the number is in fact zero. And I showed the remaining data at the end. I prefered this instead of a long running elaboration on `errno`. You are right on that using the string is better, but _if I was in fact testing for valid input_. Instead, was clarifying an ambiguity of strtol(), @chqrlie – arfneto Aug 20 '20 at 15:48