7

'when there is no successful assignments' i know that scanf returns 0 to indicate it, but is that the only thing that it does? this is my code:

 #include<stdio.h>
  int main(void) {
      int val,x;
      x=scanf("%d",&val);
     if(x==1)
       printf("success!");
     else{
       printf("try again\n");
       scanf("%d",&val);
      }
   return 0;
 }

if i enter a number, it works fine but if i enter a character scanf doesn't work anymore, this is what i get:

   k
   try again
   process returned 0 (0x0)  execution time :2.578 s
   press any key to continue.
   _

meaning that it doesn't allow me to enter a new value, why is that? is there something wrong in the code? if yes how can i fix it? should i stop using scanf?

Nous Sa Smily
  • 73
  • 1
  • 7
  • 3
    Don't use `scanf`. Use `fgets()` to read a whole line, and then use `sscanf` to process the data in the line. – Barmar Dec 31 '15 at 23:58
  • 2
    Don't use `sscanf` either. Use `fgets()` to read a whole line and then use `strtol` and friends to process the data in the line. Only those functions are reliable in the face of arbitrarily malformed input. – zwol Jan 01 '16 at 00:01
  • thank you! i will try those solutions! – Nous Sa Smily Jan 01 '16 at 00:12

2 Answers2

9

When scanf doesn't work, the invalid data is still left in the stream. You'll have to read and discard the data from the stream first before you can enter more data.

#include<stdio.h>
int main(void) {
   int val,x;
   x=scanf("%d",&val);
   if(x==1)
      printf("success!");
   else{
      // Discard everything upto and including the newline.
      while ( (x = getchar()) != EOF && x != '\n' );
      printf("try again\n");
      scanf("%d",&val);
   }
   return 0;
}
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • You should not be teaching people to use `scanf`; you should be teaching the alternatives instead. I know you know what they are. – zwol Jan 01 '16 at 00:01
  • thank you very much! if you can just explain what you did, please! – Nous Sa Smily Jan 01 '16 at 00:10
  • 1
    @NousSaSmily, that `x = gechar()` gets the next character from the input stream. The `while` loop continues to do that as long as `x` is not `EOF` and it is not `'\n'`. If `x` is equal to `EOF` or `'\n'`, the program breaks out of the `while` loop. – R Sahu Jan 01 '16 at 00:13
  • 2
    @zwol, I understand the dangers of `scanf`. However, I don't forbid its usage. When writing production code, I never ignore the return value of `scanf`. – R Sahu Jan 01 '16 at 00:16
  • @RSahu If you truly understood the dangers of `scanf` you *would* forbid its usage. (Note in particular that `%s` is every bit as dangerous as `gets`, and that numeric overflow is *undefined behavior.*) – zwol Jan 01 '16 at 00:18
  • @zwol, you teach people to use scanf because there are oodles of lines of code out there that use it. If we don't teach it, no one will be able to perform maintenance. – nicomp Jan 01 '16 at 00:21
  • @zwol, you are right. I don't use `%s`. I use `%d` to read the length of the string, then make sure I have a buffer to hold enough characters, then use `fread`. I don't think about numeric overflow. I suspect that is a habit from the kinds of input files I encounter in my field of work. – R Sahu Jan 01 '16 at 00:23
3

The scanf family of functions are broken-as-specified and should never be used for anything.

The correct way to write this program is to use getline, if available, or fgets otherwise, to read an entire line of user input. Then use strtol to convert the input to a machine integer, taking care to check for errors:

errno = 0;
result = strtol(line, &endptr, 10);
if (endptr == line || *endptr != '\n' || errno)
   // invalid input
zwol
  • 135,547
  • 38
  • 252
  • 361