C: using strtol endptr is never NULL, cannot check if value is integer only?

Georgi Angelov picture Georgi Angelov · Sep 24, 2013 · Viewed 7k times · Source

So here is the problem. I have a set of data that is supposed to be :

int int int int ....

however, I want that if I have 1asdas 2 , I want to be able to catch the "asdas" part. However, at this moment, if I only have 1 2, then endptr is not NULL and so I cannot check if the value was only a digit or a digit and letters. Here is my code:

            else if(token != NULL && token2 != NULL && token3 == NULL){
                    //we POSSIBLY encountered row and column values for the matrix
                    //convert the two numbers to longs base 10 number
                    int row = strtol(token, &result, 10);
                    int col = strtol(token2, &result2, 10);
                    printf("Result is %s and result2 is %s\n", result, result2);
                    //check to see if both numbers are valid
                    //this will be true if there were only 2 digits on the line
                    if(!result && !result2){
                            //SUCCESSFULL parsing of row and column
                            printf("SUCCESSFUL PARSING\n");
                    }
            }

Thanks!

Answer

zwol picture zwol · Sep 24, 2013

Assuming that earlier code has already split up the line into individual numbers, then the check you want is

errno = 0;
long row = strtol(token, &endtoken, 10);
if (*endtoken != '\0')
    fprintf(stderr, "invalid number '%s' (syntax error)\n", token);
else if (endtoken == token)
    fprintf(stderr, "invalid number '' (empty string)\n");
else if (errno)
    fprintf(stderr, "invalid number '%s' (%s)\n", token, strerror(errno));
else
    /* number is valid, proceed */;

strtol will never set endtoken to a null pointer; it will set it to point to the first character that is not a digit. If that character is the NUL string terminator (note the slightly different spelling), then the entire string was a valid number, unless endtoken == token, which means that you gave strtol the empty string, which probably doesn't count as a valid number. The errno manipulation is necessary to catch numbers which were syntactically correct but outside the range of long.

You might be able to simplify your code by pulling numbers directly out of the line buffer rather than splitting it up first: assuming there are supposed to be exactly two numbers on any given line,

char *p = linebuf;
char *endp;
errno = 0;
long row = strtol(p, &endp, 10);
if (endp == p || !isspace(p) || errno)
  /* error, abandon parsing */;
p = endp;
long col = strtol(p, &endp, 10);
if (endp == p || p != '\0' || errno)
  /* error, abandon parsing */;