strtol() and zero

M

Marlene Stebbins

Suppose I'm using strtol() to convert a command line string
to a number and I want to check that the input to strtol() is
not non-numeric. strtol() returns zero if input is non-numeric,
so I can write something like this:

if((x = strtol(argv[1], NULL, 10))==0)
exit(EXIT_FAILURE);

That catches non-numeric input alright, but zero is a perfectly
good number that might be input to my program. How can I use
strtol() to convert zero while checking for non-numeric input?
 
J

Jens.Toerring

Marlene Stebbins said:
Suppose I'm using strtol() to convert a command line string
to a number and I want to check that the input to strtol() is
not non-numeric. strtol() returns zero if input is non-numeric,
so I can write something like this:
if((x = strtol(argv[1], NULL, 10))==0)
exit(EXIT_FAILURE);
That catches non-numeric input alright, but zero is a perfectly
good number that might be input to my program. How can I use
strtol() to convert zero while checking for non-numeric input?

That's what the second argument to strtol() is good for: if you
pass it a pointer to a char pointer it returns the position in
the input string where the conversion stopped. If that's identi-
cal to the string you passed to strtol() you know that nothing
got converted and thus the input was non-numeric. So use it like

char *ep;

x = strtol( argv[ 1 ], &ep, 10 );
if ( argv[ 1 ] == ep )
exit( EXIT_FAILURE );

Of course, you should also check that the input value didn't
under- or overflow, i.e. was less than LONG_MIN or larger than
LONG_MAX - in that case the return value is either LONG_MIN or
LONG_MAX, respectively, and errno is set to ERANGE.

Regards, Jens
 
E

Eric Sosman

Marlene said:
Suppose I'm using strtol() to convert a command line string
to a number and I want to check that the input to strtol() is
not non-numeric. strtol() returns zero if input is non-numeric,
so I can write something like this:

if((x = strtol(argv[1], NULL, 10))==0)
exit(EXIT_FAILURE);

That catches non-numeric input alright, but zero is a perfectly
good number that might be input to my program. How can I use
strtol() to convert zero while checking for non-numeric input?

It only catches some non-numeric input. For example, try
it on "99bottles" ...

strtol() uses three count them three channels to tell you
about conversion errors. First, there's the returned value:
zero if nothing could be converted, LONG_MIN or LONG_MAX if
the input was numeric or out of range. Of course, these three
values could also be returned by a successful conversion, as
you've observed.

If you get LONG_MIN or LONG_MAX, you can distinguish range
errors from legitimate conversions by setting `errno' to zero
before the call and checking whether it's been set to ERANGE
afterward. (Actually, I think Section 7.5 paragraph 3 of the
Standard implies that `errno' will only be set to ERANGE if an
error occurs, assuming it wasn't ERANGE already, so checking
for LONG_MIN and LONG_MAX might be avoidable. Gurus?)

Finally, you can distinguish "no conversion" from an actual
zero (and catch the "99bottles" problem) by making use of the
second argument, so strtol() can tell you where conversion
stopped.

All this rummaging around is inconvenient, and it's probably
best to write a wrapper function to shield yourself from the
unpleasantness. (Sad, isn't it, that a Standard library function
is so unpleasant -- but we are victims of "prior art" here.)
One simple-minded wrapper might take the string and a pointer
to a variable that receives the converted value, and return a
code indicating whether all went well, something like

#include <stdlib.h>
#include <limits.h> /* might not be needed */
#include <errno.h>

/* Returns 0 for success, -1 for failure */
int wrapper(const char *string, long *value) {
char *end;

errno = 0; /* anything other than ERANGE */
*value = strtol(string, &end, 10);

/* the first part of this test might be unneeded */
if ((*value == LONG_MIN || *value == LONG_MAX)
&& errno == ERANGE)
return -1; /* input out of range */

if (end == string)
return -1; /* no conversion possible */

if (*end != '\0')
return -1; /* trailing garbage */

return 0; /* success! */
}

Fancier wrappers are possible too, of course.
 
A

Al Bowers

Marlene said:
Suppose I'm using strtol() to convert a command line string
to a number and I want to check that the input to strtol() is
not non-numeric. strtol() returns zero if input is non-numeric,
so I can write something like this:

if((x = strtol(argv[1], NULL, 10))==0)
exit(EXIT_FAILURE);

That catches non-numeric input alright, but zero is a perfectly
good number that might be input to my program. How can I use
strtol() to convert zero while checking for non-numeric input?

You need to use the endp feature(2nd parameter) of function
endp.

char *endp;
s = strtol(argv[1], &endp, 10);

You then check the value to what endp points which will
help you determine if a string is what you consider a valid zero.
You should study the description of this function in detail as
it offers many robust features that you can use.

Example:

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

int main(void)
{
char input[6][16] = {"","0a"," 0", "0 ", " 0 ","0"};
char *endp;
long i, value;

for(i = 0; i < 6; i++)
{
value = strtol(input,&endp,10);
if(!value && endp != input && *endp == '\0' &&
!isspace((unsigned char)input[0]))
printf("\nThe string \"%s\" is in fact zero\n",input);
else printf("The string \"%s\" is not zero\n",input);
}
return 0;
}
 
J

Joe Wright

Marlene said:
Suppose I'm using strtol() to convert a command line string
to a number and I want to check that the input to strtol() is
not non-numeric. strtol() returns zero if input is non-numeric,
so I can write something like this:

if((x = strtol(argv[1], NULL, 10))==0)
exit(EXIT_FAILURE);

That catches non-numeric input alright, but zero is a perfectly
good number that might be input to my program. How can I use
strtol() to convert zero while checking for non-numeric input?

Assume this prototype..

long strtol(const char *s, char **endp, int base);

Rather than passing NULL as the second argument, pass the address of
a local char* like this..

long x;
char *end;
x = strtol(argv[1], &end, 10);
if (argv[1] == end) exit(EXIT_FAILURE);
 
J

Jack Klein

Suppose I'm using strtol() to convert a command line string
to a number and I want to check that the input to strtol() is
not non-numeric. strtol() returns zero if input is non-numeric,
so I can write something like this:

if((x = strtol(argv[1], NULL, 10))==0)
exit(EXIT_FAILURE);

That catches non-numeric input alright, but zero is a perfectly
good number that might be input to my program. How can I use
strtol() to convert zero while checking for non-numeric input?

Explanation and illustration:

http://jk-technology.com/c/code/strtol.html
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

this calls and checks strtol() correctly? 7
dice generator problems 43
string to int 5
hex to int 12
pointer arithmetic error? 17
C program: memory leak/ segmentation fault/ memory limit exceeded 0
strtol() 1
code works 11

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,070
Latest member
BiogenixGummies

Latest Threads

Top