The scanf
function works this way per the specification:
An input item shall be defined as the longest sequence of input bytes (up to any specified maximum field width, which may be measured in characters or bytes dependent on the conversion specifier) which is an initial subsequence of a matching sequence. [Emphasis added.]
In your example, the following C string represents the contents of stdin when the first scanf
call requests input: "4.4\n"
.
For this initial call, your format string consists of a single specifier, %d
, which represents an integer. That means that the function will read as many bytes as possible from stdin which satisfy the definition of an integer. In your example, that's just 4
, leaving stdin to contain ".4\n"
(if this is confusing for you, you might want to check out what an integer is).
The second call to scanf
does not request any additional input from the user because stdin already contains ".4\n"
as shown above. Using the format string %f
attempts to read a floating-point number from the current value of stdin. The number it reads is .4
(per the specification, scanf
disregards whitespace like \n
in most cases).
To fully answer your question, the problem is not that you're misusing scanf
, but rather that there's a mismatch between what you're inputting and how you're expecting scanf
to behave.
If you want to guarantee that people can't mess up the input like that, I would recommend using strtol
and strtod
in conjunction with fgets
instead.