Take for example, this simple code snippet:
So what? Looks normal to me, what can go wrong?
When we run this program and type a value other than 10, we would expect the program to halt and not close until we press a key, right? Wrong. You'll notice that it exits immediately! How can that be you say? Turns out, scanf() isn't too good when it comes to flushing characters from the input buffer, in this case stdin. I guess I should also note that scanf() is actually not a very safe function in terms of buffer overruns. The actual problem is that scanf() ignores all characters that did not match the input format. When we press ENTER, a carriage return gets put on the input stream - this does not match the format supplied and scanf() does not remove it from the input.
The problem is that when control finally transfers to the getchar() function, it notices that there is still characters on the input buffer, and returns immediately. This makes sense when we realize that getchar() doesn't usually return until someone presses a key (the function basically sits there waiting for data from stdin, and when it gets some it says "OK I'm done!").
Because of this behavior we can also get all sorts of bugs if a user inputs invalid data (infinite loops come to mind).
Buffer overruns? Infinite loops? They don't sound too good! How do I solve this?
Some compilers (Microsoft VC++ compiler is one example) will issue either an error or a warning during the build process that alerts you that you have used deprecated or insecure functions like scanf() and often offer alternatives. The obvious solution though is to make sure that we flush the input buffer before we call a function such as getchar(), like so:
However that still doesn't solve the real issues with scanf() (i.e. buffer overruns and infinite loops). If you are using Microsoft VC++ Compiler and are paying attention to its warnings, you'll notice it offers sscanf() as an alternative function, however this function doesn't quite work the exact same way as scanf() so you can't just go ahead and find/replace! What we need to do is read into our own buffer a certain amount of bytes from the stdin stream and then pass that to sscanf() for processing, like below:
And there we have it - both problems solved!
Edited by tompsonn - 9/16/12 at 12:45am
Code:
int someValue = 0;
printf( "Type a value: " );
scanf( "%d", &someValue );
if ( someValue == 10 )
{
// do something
return;
}
// wait for keypress (pause program)
getchar();
So what? Looks normal to me, what can go wrong?
When we run this program and type a value other than 10, we would expect the program to halt and not close until we press a key, right? Wrong. You'll notice that it exits immediately! How can that be you say? Turns out, scanf() isn't too good when it comes to flushing characters from the input buffer, in this case stdin. I guess I should also note that scanf() is actually not a very safe function in terms of buffer overruns. The actual problem is that scanf() ignores all characters that did not match the input format. When we press ENTER, a carriage return gets put on the input stream - this does not match the format supplied and scanf() does not remove it from the input.
The problem is that when control finally transfers to the getchar() function, it notices that there is still characters on the input buffer, and returns immediately. This makes sense when we realize that getchar() doesn't usually return until someone presses a key (the function basically sits there waiting for data from stdin, and when it gets some it says "OK I'm done!").
Because of this behavior we can also get all sorts of bugs if a user inputs invalid data (infinite loops come to mind).
Buffer overruns? Infinite loops? They don't sound too good! How do I solve this?
Some compilers (Microsoft VC++ compiler is one example) will issue either an error or a warning during the build process that alerts you that you have used deprecated or insecure functions like scanf() and often offer alternatives. The obvious solution though is to make sure that we flush the input buffer before we call a function such as getchar(), like so:
Code:
fflush( stdin ); // remove all data from the stdin buffer
getchar(); // now waits as expected for a keypress.
However that still doesn't solve the real issues with scanf() (i.e. buffer overruns and infinite loops). If you are using Microsoft VC++ Compiler and are paying attention to its warnings, you'll notice it offers sscanf() as an alternative function, however this function doesn't quite work the exact same way as scanf() so you can't just go ahead and find/replace! What we need to do is read into our own buffer a certain amount of bytes from the stdin stream and then pass that to sscanf() for processing, like below:
Code:
/*
* GetInput: An alternative to C runtime scanf to clean up flawed data
* entry in C where scanf does not consume the content of stdin if the
* conversion fails (i.e. char entered for int).
*/
int GetInput( const char* format, void* input )
{
char buffer[ 100 ];
fgets( buffer, 99, stdin );
return sscanf( buffer, format, input );
}
And there we have it - both problems solved!
Edited by tompsonn - 9/16/12 at 12:45am










