GIDNetwork > Things to Avoid in C/C++ -- scanf / epilogue, Part 9
Register
« Things to Avoid in C/C++ -- scanf / number, Part 8 Beginning Python Tutorial (Part 5) »

Things to Avoid in C/C++ -- scanf / epilogue, Part 9

by: WaltP - Oct 01, 2005

scanf() / So what's a programmer to do?

scanf() is not designed for production code, but for creating test programs to see if other aspects of the program are working. scanf() will replace the complicated input routines so that other modules can be exercised and perfected. Then the scanf() is replaced with the real input function that gets the actual data from a file, a device, wherever the actual data is stored.

And if that data is in fact from a user, the input modules will probably consist of a suite of routines that parse bits and pieces of the actual input string (read by fgets() probably) and can handle all different kinds of user errors without crashing or looping.

When reading anything, scanf() will skip all leading whitespace. Then it grabs all the characters that fit the format specified. At the first invalid character it stops, leaving this character for the next read. For strings, invalid characters are all whitespace, defined as the following:

Generic Code Example:

 Hex Dec Ctrl Name
0x09  9  ^I  Tab
0x0A 10  ^J  Line Feed
0x0B 11  ^K  Verticle Feed
0x0C 12  ^L  Form Feed
0x0D 13  ^M  Carriage Return
0x1A 26  ^Z  End of File
0x20 32      Space

The character input is the main offender, since it reads any character that's available. Therefore, after reading anything with scanf(), following it with a single character read will always read whatever is left, and not what you were hoping to type in. So...

  • %d -- works fine

  • %f -- works fine

  • %s -- ignores preceeding whitespace and reads one 'word'

  • %c -- rarely works as expected

So, reading numbers is OK, reading a word works, but sentences don't. And attempting to read characters is just asking for trouble without a special function.

Here is a function you can use to read a single non-whitespace character. This would be used in place of scanf("%c", &ch) to make sure you actually get to input the value:

C/CPP/C++ Code Example:

int  getCharacter()
{
    int ch;         // define the character
    do              // loop until a good character is read
    {
        ch = getchar();             // read a character
    } while ( (ch == 0x20)  ||      // check for SPACE
             ((ch >= 0x09)  &&      // check for the 
              (ch <= 0x0D))         //    other whitespace
            );              
    return ch;
}

This will keep reading until there is a non-whitespace character entered, effectively clearing the buffer from previous scanf() calls.

This function will accept only printable non-whitespace (a more usable function):

C/CPP/C++ Code Example:

int  getCharacter()
{
    int ch;         // define the character
    do              // loop until a good character is read
    {
        ch = getchar();         // read a character
    } while ((ch <= 0x20) ||    // check above SPACE
             (ch >= 0x7F)       // check below the last 
            );                  //    ASCII char
    return ch;
}

So now you have no excuse for complaining my scanf() doesn't work! You now know why.

Bottom line -- try to avoid it except in testing. And definitely avoid it when reading characters.

caveat:
The problem with scanf() and characters also exists with getchar() too. The reason is C/C++ input is buffered -- you must type ENTER to get the input to read. So the above functions are useful even when scanf() is not being used.

Would you like to comment? This story has been viewed 44,107 times.
« Things to Avoid in C/C++ -- scanf / number, Part 8 Beginning Python Tutorial (Part 5) »

__top__

Copyright © GIDNetwork™ 2001 - 2017

Another website by J de Silva

Page generated in : 0.01430 sec.