The main issue is that its hard to understand all these concepts when you are just starting with the language. Like where the hell does scanf
take the input? What is buffering?
I won't talk about technical terms, you can always google them if you want to go deep, will try to keep it simple. Also I am just talking from unix side and donno anything about windows.
scanf(3)
calls read(2)
internally and printf(3)
calls write(2)
. So why don't we use read(2)
and write(2)
directly? The issue is that read(2)
/write(2)
are slow because for them a switch needs to be made to from user mode to kernel mode and this is a time taking process. What scanf()
and printf()
do is that they stay in user mode and collect the information there and read/write it in one go i.e. they store it in a buffer for time being.
Now this makes some more things possible. As the input hasn't reached your variable yet and is in the buffer, scanf()
can do additional checks. Like in your case, check if the input is as per your format specifier. If not it won't assign it to your variable and return. But scanf won't clear that buffer where it received input. In your case in scanf()
, when your input is not as per %f
, it returns 0 and your if condition makes it go up and input again. But it never cleared the buffer. So the buffer contains the same input as from before and it acts again on it causing the same problem again. This continues infinitely.
Now to the solution:
This is a little confusing due to "standards" issue.
When you see the manpage of fflush(3)
,
It states:
For input streams, fflush() discards any buffered data that has been fetched from the underlying file, but has not been consumed by the application.
But then at the bottom of the page,
The standards do not specify the behavior for input streams. Most other implementations behave the same as Linux.
So fflush(stdin)
doesn't seem to work like that on your system. (just as it doesn't on mine)
Best ways to achieve this have already been discussed in many questions:
How to solve your problem:
Scanf skips every other while loop in C
Better way:
Using fscanf() vs. fgets() and sscanf()
Another way is to change fflush(stdin)
to fpurge(stdin)
(ITS NOT PORTABLE AND NOT STANDARD).
From the manpage of fpurge(3)
which I don't see being discussed anywhere:
The function fpurge() clears the buffers of the given stream. For
output streams this discards any unwritten output. For input streams
this discards any input read from the underlying object but not yet
obtained via getc(3); this includes any text pushed back via
ungetc(3).
Also have a look at why its not a good idea to use goto
in such scenarios. What is wrong with using goto?