2

I'm writing a C program that accepts a list of unsigned long long numbers as input from the command line. How do I parse them and store in an array? It seems that strtoull might help, but how do I use it?

Here is my code:

#include<stdio.h>

main (int argc, char *argv[])
{
  unsigned long long M[1000];
  int i;
  printf("length: %d\n", argc - 1);
  for(i = 1; i < argc; i++) {
    M[i] = strtoull(argv[i], NULL, 10);
    printf("%llu\n", M[i]);
  }
  return 0;
}

It works when parameters are small, but when I enter a huge number (say, 123456789012345), it is not parsed correctly. What am I doing wrong?

Māris Ozols
  • 123
  • 1
  • 6
  • 1
    You didn't include . Didn't the compiler give you a warning about strtoull not having a prototype? Functions which are not declared are assumed to return an `int`, which is not the case for `strtoull` – rici Oct 05 '13 at 18:15

3 Answers3

4

An easy approach is to use sscanf() on argv[i] with %llu to parse unsigned long long integers. Here's some sample code:

#include <stdio.h>

int main(int argc, char *argv[]) {
    unsigned long long example;
    int i;
    for (i = 1; i < argc; i++) {
        sscanf(argv[i], "%llu", &example);
        printf("Argument: %llu\n", example);
    }
    return 0;
}

You can use strtoull as well, in fact, I think scanf() uses it internally. Beware of overflows though, scanf() is not very well behaved with setting errno in appropriate occasions. I've had some problems with it. But you should be cool with unsigned long long, you really need a very big number to cause overflow.

Filipe Gonçalves
  • 19,404
  • 6
  • 42
  • 65
  • -1 `strtoull` *is* the correct answer, `sscanf` on strings that are known to be numbers is just overkill. You are not really helping the OP, he just has an error in his code. – Jens Gustedt Oct 05 '13 at 20:38
  • 2
    Show me some documentation or link where that is thoroughly explained, and I will edit my answer. – Filipe Gonçalves Oct 05 '13 at 21:42
  • 2
    Sorry? I know strtoull is part of stdlib.h. Did you read my comment? I was just asking where can I read about scanf being overkill to parse a number. – Filipe Gonçalves Oct 05 '13 at 22:59
  • I read your comment, but obviously you didn't re-read it. It is not precise about which part of my comment you are worrying. For the part about the overkill, I don't think one needs a reference for it. Why should you use a function that dynamically parses a format string at run time, where there is a perfect solution that does the task directly? – Jens Gustedt Oct 06 '13 at 07:06
  • 1
    It's really irrelevant, both programs are equally efficient. I tried running the version with sscanf with every number from 1 to 1000, and timed it. Then I changed it to use strtoull, and the time taken was the same. Try it yourself, make a shell script to run the code in a loop. – Filipe Gonçalves Oct 06 '13 at 08:58
2

Yes, you can use strtoull. Here's an example framework:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
// include other headers as needed...


int main( int argc, char *argv[] )
{
    int i;
    unsigned long long big_value;

    // If there are no command line parameters, complain and exit
    //
    if ( argc < 2 )
    {
        fprintf( stderr, "Usage: %s some_numeric_parameters\n", argv[0] );
        return 1;
    }

    for ( i = 1; i < argc; i++ )
    {
        big_value = strtoull( argv[i], NULL, 10 );

        if ( errno )
        {
            fprintf( stderr, "%s: parameter %s: %s\n", argv[0], argv[i], strerror(errno) );
            return 2;
        }

        // Do some stuff with big_value

        ...
    }

    return 0;
}
lurker
  • 53,004
  • 8
  • 60
  • 93
  • 1
    Perhaps you should emphasize on the fact that the main difference of your answer to the code in the question is the use of the correct header files. – Jens Gustedt Oct 05 '13 at 20:39
  • When I run this code, it seems to have the same problem as my original code. That is, if the numbers supplied as parameters through command line are too large (more than 10 digits), I get a wrong value if I try to print them by putting `printf("%d: %llu\n", i, big_value);` where you have `...` at the moment. – Māris Ozols Oct 05 '13 at 21:21
  • 1
    @MārisOzols sorry that was my fault. The inclusion of `stdlib.h` is required since it prototypes `strtoull`. I had inadvertently deleted it on one of my edits. I have updated accordingly. – lurker Oct 05 '13 at 21:31
  • I see, now it works correctly! I also tried adding `stdlib.h` to my original code, and now it worked as well. I have already accepted the other answer, but thanks a lot anyway! – Māris Ozols Oct 05 '13 at 21:37
  • @MārisOzols no worries. `stdlib.h` is essential since otherwise the return value of `strtoull` will be taken as an integer. The compiler should give a warning about that (default for `gcc` is to issue a warning). – lurker Oct 05 '13 at 21:39
  • @MārisOzols, since this here is really the better answer, you should change your acceptance for this one here. – Jens Gustedt Oct 05 '13 at 22:16
0

Just remember that command line arguments are all strings. If you need to convert any to numbers (integer or real), then look at the man pages for the following functions:

int atoi(const char *nptr);
long atol(const char *nptr);
long long atoll(const char *nptr);
double atof(const char *nptr);
long int strtol(const char *nptr, char **endptr, int base);
long long int strtoll(const char *nptr, char **endptr, int base);
double strtod(const char *nptr, char **endptr);
float strtof(const char *nptr, char **endptr);
long double strtold(const char *nptr, char **endptr);