2

I have been stuck up with this issue. The requirement of the problem is very simple. All I want to do is check user input and allow the user to enter only lower case letters. The other constraint is I want to do it using only scanf(). I know I can use gets() and other input functions, but still, for the sake of understanding it better, I would like to use scanf() to do so.

I have tried the following on GCC:

char str[100000];
return_value=scanf("%99999[a-z]",str);
if(return_value==0 || return_value==EOF)
{
  printf("illegal input");
}
else
  printf("input accepted");

The following works absolutely as expected. So if the user tries to enter any string in upper case letters the code simply prints out: "illegal input".

The problem comes up when i try to put the above code in a finite while loop. For example:

int counter=0; 
char str[100000];
scanf("%2d",&counter);
while(counter>0)
{
  fflush(stdin);
  return_value=scanf("%99999[a-z]",str); //note
  if(return_value==0 || return_value==EOF)
  {
    printf("illegal input");
  }
  else
    printf("input accepted");
  counter--;
 }//end of while

In the above case as soon as user enters the value of the variable "counter" and presses the return key, the control straight away goes and prints "illegal input", without even waiting for the user to input a string.

To correct this error I tried putting the following in place of the line marked as note:

return_value=scanf("%99999s[a-z]",str); //note

or even this:

return_value=scanf("%99999c[a-z]",str); //note

In either case although the user is allowed to enter the input string after entering the 'counter' variable's value, the user input sanitization is not done, i.e even if the user enters a string consisting of uppercase characters, the output is not "illegal input" (as it should have been) but rather "input accepted".

Now can some one please explain this to me. Where am i going wrong or am i simply overlooking something and doing some silly mistake?

Sean Dawson
  • 5,587
  • 2
  • 27
  • 34
qre0ct
  • 5,680
  • 10
  • 50
  • 86

2 Answers2

2

fflush() is an inappropriate way to clear stdin. Instead, use scanf to read until EOF or just

while((c = getchar()) != '\n' && c != EOF) { /* Discard */ }

Also, I would suggest scoping even single statements such as the else.

BSull
  • 329
  • 2
  • 10
  • ok.. i partly agree... but would be glad if oyu could give some explanation on why is fflush considered inappropriate. And secondly, i know of this technique you mentioned, but i;d still like to use scanf and do the required. Any suggestions would be appreciated. – qre0ct Sep 16 '12 at 11:55
  • @geek_ji Because you are not allowed to use fflush on an input stream. The result is undefined behaviour. – Juri Robl Sep 16 '12 at 12:00
  • fflush(stdin) is undefined by ANSI C. Meaning it's bad practice to use it, it's unclear, and it has a good chance of not working. I believe that goes for fflush on any input stream or "read." getchar is basically scanf("%c", &c). – BSull Sep 16 '12 at 12:01
  • @Juri Robl thanks guys... great explanation.. ! Now I can not use getchar. The requirement of the problem has this as a constraint. I HAVE TO use scanf itself. So how do you guys suggest it be used so that the user is allowed to input only lower case letters ? – qre0ct Sep 16 '12 at 12:05
  • 1
    @geek_ji Use the scanf "workaround" BSull suggested to replace getchar. – Juri Robl Sep 16 '12 at 12:06
  • For reference, [7.21.5.2/2](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf): "2 If `stream` points to an output stream or an update stream in which the most recent operation was not input, the `fflush` function causes any unwritten data for that stream to be delivered to the host environment to be written to the file; *otherwise, the behavior is undefined* ." Emphasis mine. – John Bode Sep 16 '12 at 13:21
1

You're trying to read again and again the bad input. If you want to skip, for example, one char, you have to do, in case of user entering bad input, scanf("%.*s") -> this will skip everything till next \n.

Explanation: if scanf() fails, it reads nothing - so, when it tries to read again, it will start from the same place it failed previously.

nothrow
  • 15,882
  • 9
  • 57
  • 104
  • I think this is correct, but it's not very clear. What is meant is that the input on stdin *doesn't go away*. So the bad characters remain and are read by scanf() on the next iteration of the loop. –  Sep 16 '12 at 11:43
  • but i did use fflush(stdin) at the start of the while loop. Will it simply not to take care of the cleaning up ?? – qre0ct Sep 16 '12 at 11:45
  • @Yossarian... uuh... dude m sorry but i could not really understand what you meant.... would you please elaborate – qre0ct Sep 16 '12 at 11:46
  • @Yossarian and also how would your suggested method let me restrict user input to only lower case characters ? – qre0ct Sep 16 '12 at 11:56