Home > database >  atoi() accepting strings mixed with number
atoi() accepting strings mixed with number

Time:11-19

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.

  1. Out of range for an int like "12345678901234567890", but not the same length "00000000000000000001".

  2. 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".

  3. 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;
}
  • Related