I initially didn't want to write an answer and left comments behind. I'd like
to expand on Jean-François Fabre's answer.
The problem with the scanf
family is that they don't do what most people
believe they do and then they are left confused as to why it does something "strange". In reality they scan input based on an format and assign values to
variables (passed via pointers). When they encounter an error, i.a. something
doesn't match to the format, then they stop.
With the format "%d"
you are just saying read an integer. The format doesn't
say "read an integer and only an integer". To do that you would need to also
exclude everything else and if I'm not mistaken it would be something like
this "%d[^0-9]*"
(I haven't tested it to see if I'm right).
That's why the user input 4.5
is accepted by
scanf
. Note that scanf
is not doing it incorrectly, you are specifying it
incorrectly, because you assume, that "%d"
means "and integer and integer
only".
As you can see, it is pretty hard to come up with a format that catches
everything and also tells you when the user made an error. User input aka what
the user enters is random and can contain (unintentionally) errors, miss the
format, etc. So you end up with very complex formats to just determine if the
user added a dot at the end and fail if the user does that.
That's why my advice is to read the while input via fgets
and then use something better
to parse the input like strtol
or even sscanf
if you have a good format.
Here an example for the usage of strtol
:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
const char *entries[] = { "4.5", "4", "some random text" };
char *ptr;
int i;
for(i = 0; i < sizeof entries / sizeof *entries; ++i)
{
long int res = strtol(entries[i], &ptr, 0);
if(*ptr != '\0') {
printf("The input '%s' is not an integer. The non-integer is '%s'\n", entries[i], ptr);
} else {
printf("The input '%s' is an integer: %ld\n", entries[i], res);
}
}
return 0;
}
which returns
The input '4.5' is not an integer. The non-integer is '.5'
The input '4' is an integer: 4
The input 'some random text' is not an integer. The non-integer is 'some random text'
This is a more precise way to check if the whole input is an integer or not.