As almost everyone says, it is better to use fgets(..., stdin) to solve this problem.
In the following link, I suggested a safe and proper technique that will allow you to replace scanf() a safer method using a solid macro :
A macro that safely replaces scanf ()
The macro I proposed (working with compatible C99 compilers) is safe_scanf() , as shown in the following program:
#include <stdio.h> #define safe_scanf(fmt, maxb, ...) { \ char buffer[maxb+1] = { [maxb - 1] = '\0' }; \ fgets(buffer, maxb+1, stdin); \ if ((buffer[maxb - 1] != '\0') && (buffer[maxb - 1] != '\n')) \ while(getchar() != '\n') \ ; \ sscanf(buffer, fmt, __VA_ARGS__); \ } #define MAXBUFF 20 int main(void) { int x; float f; safe_scanf("%d %g", MAXBUFF+1, &x, &f); printf("Your input was: x == %d\t\tf == %g", x, f); return 0; }
You need to adjust the MAXBUFF value according to your needs ...
Although the safe_scanf() macro is pretty strong,
There is some weakness in using the macro approach:
Lack of type checking for parameters, lack of "return" values (which are hardly different from the "true" scanf() function, which returns int , with valuable information for checking errors), etc.
All these problems have a solution, but this is part of a different topic ...
Perhaps the most accurate solution is to define the my_scanf() function with a variable number of parameters by calling the stdarg.h library, combined with the combination of fgets() and vsscanf() . Here you have the code:
#include <stdio.h> #include <stdarg.h> int my_scanf(const char* fmt, const unsigned int maxbuff, ...) { va_list ptr; int ret; if (maxbuff <= 0) return EOF; /* Bad size for buffer[] */ char buffer[maxbuff+1]; buffer[maxbuff-1] = '\0'; /* Quick buffer cleaning... */ if (fgets(buffer, maxbuff+1, stdin) == NULL) return EOF; /* Error detected */ else { if ((buffer[maxbuff-1] != '\n') && (buffer[maxbuff-1] != '\0')) /* Condition logically equivalent to: fgets() has not reached an '\n' */ while (getchar() != '\n') ; /* "Flushing" stdin... */ va_start(ptr, maxbuff); ret = vsscanf(buffer, fmt, ptr); va_end(ptr); return ret; } } #define MAXBUFF 20 int main(void) { int x; float z; int scanf_ret = my_scanf("%d %g", MAXBUFF, &x, &z); printf("\nTest:\nx == %d\nz == %g\n scanfret == %d", x, z, scanf_ret); getchar(); return 0; }
The my_scanf () function has a prototype
int my_scanf(const char* fmt, const int maxbuff, ...);
It accepts an fmt format string, which behaves just like any other scanf() -like. The second parameter is the maximum number of characters that will be effectively received from standard input (keyboard).
The return value is an int that is EOF if MAXBUFF not meaningful, or an input error has occurred. If a non-negative value is returned, then it will be returned by the standard sscanf() or vsscanf() functions.
Inside the function, MAXBUFF incremented by 1 because fgets() creates space for the extra character '\ 0'.
Non- MAXBUFF MAXBUFF values MAXBUFF immediately discarded.
fgets() will read a line read from stdin (keyboard) with no more than MAXBUFF , including '\ n'.
If the user entered a very long line, then it will be truncated, and in order to discard all characters until the next "\ n" ( ENTER ), some kind of "flash" mechanism is necessary. If not, the next keyboard reading may have older characters not wanting at all.
The flushing condition is that fgets() does not reach "\ n" after reading stdin .
This is the case if and only if buffer[maxbuff - 1] not equal to '\ 0' and '\ n'.
( Check it out! )
Finally, a suitable combination of stdarg.h macros and the vsscanf() function are used to process a list of variables.