You should never use the *scanf
family, nor atoi
and friends. The correct way to write this code is
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main(void)
{
char inbuf[80], *endp;
unsigned long bet; /* negative bets don't make sense */
puts("What number do you want to bet?");
if (!fgets(inbuf, sizeof inbuf, stdin))
return 1; /* EOF - just quit */
errno = 0;
bet = strtoul(inbuf, &endp, 10);
if (endp == inbuf || *endp != '\n' || errno) {
fputs("invalid number entered, or junk after number\n", stderr);
return 1;
}
printf("Here is your number: %lu\n", bet);
return 0;
}
Some exposition, perhaps:
The only sane way to read input from the user in C is an entire line at a time. If you don't, you are very likely to get in trouble when, not if, the user types more input than you expected. The ideal way to do this is with getline
, but many C libraries do not have it, and it does make you remember to free the line-buffer. Failing that, fgets
is good enough for many purposes, as shown here.
The only correct way to convert text to machine numbers in C is with the strto*
family of functions. I use the word correct very deliberately. All the alternatives either silently ignore numeric overflow (ato*
) or, worse, trigger undefined behavior on numeric overflow (*scanf
). The usage pattern for strto*
is a little tricky, but once you get used to it, it is just boilerplate to be memorized and typed. I'll take it apart for you:
errno = 0;
It is necessary to clear errno
manually before calling strto*
, because a syntactically valid number that overflows the range of the return value is reported only by setting errno
, but success does not clear errno
. (The manpage says that a particular numeric value is returned, but that value could have resulted from correct input, so that's no help.)
bet = strtoul(inbuf, &endp, 10);
When this function call returns, bet
will be the number you wanted, and endp
will be set to the first character in inbuf
that is not a digit.
if (endp == inbuf || *endp != '\n' || errno) { /* error */ }
If endp
equals inbuf
, that means there were no digits, which is usually not considered a valid number.
If *endp
is not equal to '\n'
, that means either there was something else on the line after the number, or fgets
did not read the whole line; in either case, again, the input is not as expected. (All 64-bit unsigned numbers fit in fewer than 80 characters.)
And if errno
is nonzero, numeric overflow occurred.