Badda
Badda

Reputation: 1359

Ways of checking an unexpected user input

I have learned that one should never trust user's input. It has become an habit to check it before processing it. I use that type of functions almost always, and often wonders if there is a difference between those two versions.

Here is a simple example of what my checking functions look like :

Version 1

int checkASCII(char c) // Here we check, print error and return if it succeeded or not
{
    if (!isascii(c))
    {
        fprintf(stderr, "Error. Not an ASCII character.\n.");
        return 1;
    }
    if (!isdigit(c))
    {
        fprintf(stderr, "Error. Not a number.\n.");
        return 1;
    }
    // potentially more checks
    return 0;
}

int printASCIINumber() // So that here we just have to verify the success
{
   char c;
   c = getc(stdin);
   if (checkASCII(c))
      putc(c, stdout);
   else return 1;
   return 0;
}

Version 2

int checkASCII(char c) // Here we just check errors regardless of what failed
{
    if (!isascii(c))
      return 1;
    if (!isdigit(c)
      return 1;
    ... // potentially more checks
    return 0;
}

int printASCIINumber() // And here we verify success and print a general error message
{
   char c;
   c = getc(stdin);
   if (checkASCII(c))
      putc(c, stdout);
   else 
   {
      fprintf(stderr, "Error. Please input an ASCII number.\n");
      return 1;
   }
   return 0;
}

If there is any objective improvement to be made I am not against it too. Thanks.

Upvotes: 0

Views: 250

Answers (1)

Aconcagua
Aconcagua

Reputation: 25518

At very first: Your return values do not match the checks you make afterwards. If you consider the result being an error code, 0 indicating success, then you have to test via if(!checkASCII(c)) - if you consider the result a boolean value then you need to invert the values returned. I'd recommend in this case including <stdbool.h>, changing the return type to bool and rename the function to isASCII. This would make your intention more obvious.

Comparing your two versions, I'd say none of both is superior to the other one in general – it rather depends on the circumstances you are programming under.

Imagine you are writing some general purpose library. Then I certainly would prefer variant 2, because you do not know if console output is desired by whoever uses your library – or if console is available at all (linux daemon processes, windows services, etc). For whichever reason, the user might want to use its own logging facility instead...

On the other hand, if you write some helper function used within your program only, variant 1 can be more handy:

  • You can provide more fine grained output directly in the function directly where failure occurs - without having to evaluate some errno or return value outside your function (which could be the way of the library function to give further information about what went wrong).
  • It is convenient, espcially if your checking function is called frequently, to be able to rely on logging already been done when you call your test function, so you can just go on in your code.

Upvotes: 3

Related Questions