Using strtol to validate integer input in ANSI C

Lukaaaaaaaay picture Lukaaaaaaaay · Oct 3, 2013 · Viewed 7.4k times · Source

I am new to programming and to C in general and am currently studying it at university. This is for an assignment so I would like to avoid direct answers but are more after tips or hints/pushes in the right direction.

I am trying to use strtol to validate my keyboard input, more specifically, test whether the input is numeric. I have looked over other questions on here and other sites and I have followed instructions given to other users but it hasn't helped me.

From what I have read/ understand of strtol (long int strtol (const char* str, char** endptr, int base);) if the endptr is not a null pointer the function will set the value of the endptr to the first character after the number.

So if I was to enter 84948ldfk, the endptr would point to 'l', telling me there is characters other than numbers in the input and which would make it invalid.

However in my case, what is happening, is that no matter what I enter, my program is returning an Invalid input. Here is my code:

void run_perf_square(int *option_stats)
{
   char input[MAX_NUM_INPUT + EXTRA_SPACES]; /*MAX_NUM_INPUT + EXTRA_SPACES are defined
                                              *in header file. MAX_NUM_INPUT = 7 
                                              *and EXTRA_SPACES 
                                              *(for '\n' and '\0') = 2. */
   char *ptr;
   unsigned num=0; /*num is unsigned as it was specified in the start up code for the 
                    *assignment. I am not allow to change it*/

   printf("Perfect Square\n");
   printf("--------------\n");
   printf("Enter a positive integer (1 - 1000000):\n");
   if(fgets(input, sizeof input, stdin) != NULL)
   {
      num=strtol(input, &ptr, 10);
      if( num > 1000001)
      {
         printf("Invalid Input! PLease enter a positive integer between 1 
                  and 1000000\n");
         read_rest_of_line();        /*clears buffer to avoid overflows*/
         run_perf_square(option_stats);
      }
      else if (num <= 0)
      {
         printf("Invalid Input! PLease enter a positive integer between 1 
                  and 1000000\n");
         run_perf_square(option_stats);
      }
      else if(ptr != NULL)
      {
         printf("Invalid Input! PLease enter a positive integer between 1 
                  and 1000000\n");
         run_perf_square(option_stats);
      }
      else
      {
         perfect_squares(option_stats, num);
      }
   }
}

Can anyone help me in the right direction? Obviously the error is with my if(ptr != NULL) condition, but as I understand it seems right. As I said, I have looked at previous questions similar to this and took the advice in the answers but it doesn't seem to work for me. Hence, I thought it best to ask for my help tailored to my own situation.

Thanks in advance!

Answer

goji picture goji · Oct 3, 2013

You're checking the outcome of strtol in the wrong order, check ptr first, also don't check ptr against NULL, derference it and check that it points to the NUL ('\0') string terminator.

if (*ptr == '\0') {
  // this means all characters were parsed and converted to `long`
}
else {
  // this means either no characters were parsed correctly in which
  // case the return value is completely invalid
  // or
  // there was a partial parsing of a number to `long` which is returned
  // and ptr points to the remaining string
}

num > 1000001 also needs to be num > 1000000

num < 0 also needs to be num < 1

You can also with some reorganising and logic tweaks collapse your sequence of if statements down to only a single invalid branch and a okay branch.