For a task I need use if atoi(INPUT) == 0
to check that a users input is a valid integer and not 0. The problem is when I enter any string that starts with an integer, it is automatically accepted, even if there are non-integer characters after the integer, for example "1aaaabcc" is accepted.
I understand that atoi() is in the example I just stated, would take the 1 and ignore it, but theortically this should be wrong input from the user since it is not a valid integer. Would there be something to add to my code (without adding any libraries) or change something with atoi to fix this?
Please let me know if you need sample code in case its not clear.
CodePudding user response:
The function atoi
is an "alias" for this function call
atoi: (int)strtol(nptr, (char **)NULL, 10)
So in your case you should use the function strtol
and pass the second argument unequal to NULL
that points to a pointer. In this case you can check whether the pointer points to the end of the corresponding string.
Here is a demonstration program
#include <stdio.h>
#include <stdlib.h>
int main( void )
{
char *endptr;
int n = ( int )strtol( "A", &endptr, 10 );
printf( "n = %d, *endptr = %d\n", n, *endptr );
n = ( int )strtol( "10A", &endptr, 10 );
printf( "n = %d, *endptr = %d\n", n, *endptr );
n = ( int )strtol( "10", &endptr, 10 );
printf( "n = %d, *endptr = %d\n", n, *endptr );
}
Its output is
n = 0, *endptr = 65
n = 10, *endptr = 65
n = 10, *endptr = 0
As you can see only in the third call of the function strtol
the pointer endptr
points to the terminating zero character '\0'
. In all preceding calls it points to the letter 'A'
that has the ASCII code 65
.
You can also accept or deny strings like for example "10 "
. If to accept such a string then in this case you need to check that the tail of the string contains only white space characters.
You should attentively read the description of the function strtol
.
CodePudding user response:
aoti()
is useful for quick and dirty code but not up to the task for robust error handling.
Non-integer characters after the integer, as in "1aaaabcc"
is best detected with strtol()
.
With strtol()
, we can detect more.
Out of range for an
int
like"12345678901234567890"
, but not the same length"00000000000000000001"
.Allow non-integer characters after the integer when text is all white-space. This is reasonable as
strtol()/atoi()
accept optional leading white-space. It also allows passing an entire line of input like"1234\n"
.No conversion as in
"asd"
," "
,""
.
I recommend a helper function
// Return true on success
bool convert_string_to_int(int *dest, const char *s) {
errno = 0;
char *endptr; // Gets updated to point to the end of the conversion.
long lvlaue = strtol(s, &endptr, 0);
if (s == endptr) {
*dest = 0;
return false; // No conversion
}
if (errno == ERANGE || lvalue < INT_MIN || lvalue > INT_MAX) {
errno = ERANGE;
*dest = lvalue < 0 ? INT_MIN : INT_MAX;
return false; // Out of range.
}
*dest = (int) lvalue;
while (isspace(*((unsigned char *)endptr))) {
endptr ;
}
if (*endptr) {
return false; // Junk at the end.
}
if (errno) {
return false; // Implementation specific errors like s == NULL
}
return true;
}