The scanf()
family of functions returns the number of successful assignments made. If code is expecting three input items there is no way to tell from the value returned by sscanf()
alone whether three or more input items were provided.
The scanf()
functions operate by reading a character, attempting to match that character, making an assignment if applicable, then moving to the next character or returning from the function call. There is a conversion specifier, %n
, that stores the number of characters read in this process so far (without incrementing the number of characters read). This conversion specifier can be used to determine if the input has been exhausted by the call to sscanf()
.
The code below provides a demonstration. Lines of input gathered by fgets()
contain a newline, unless the input is too large to fit in the buffer array. Here buffer[]
is large enough to store reasonably-sized inputs, but more robust code would handle oversized inputs more carefully. When sscanf()
scans the input string, each character is read in turn until a failing match occurs or the end of the string is reached, so the number of read characters expected after matching "%d %d %d %n"
is the same as the length of the input string, including any trailing whitespace characters.
#include <stdio.h>
#include <string.h>
#define BUF_SZ 1024
int main(void)
{
char buffer[BUF_SZ];
int x, y, z;
int pos;
printf("Enter three integers: ");
fflush(stdout);
// get user input
if (fgets(buffer, sizeof buffer, stdin) != NULL) {
// first check: does input match 3 integers?
if (sscanf(buffer, "%d %d %d %n", &x, &y, &z, &pos) != 3) {
puts("Incorrectly formatted input");
} else {
// second check: did sscanf() finish at the end of the buffer?
int expected = strlen(buffer);
if (pos != expected) {
puts("Extra input in buffer");
printf("expected = %d, pos = %d\n", expected, pos);
} else {
// everything OK
printf("You entered: %d, %d, %d\n", x, y, z);
}
}
}
return 0;
}
Sample interactions:
>$ ./a.out
Enter three integers: 1 2 3
You entered: 1, 2, 3
>$ ./a.out
Enter three integers: 1 2
Incorrectly formatted input
>$ ./a.out
Enter three integers: 1 2 3 4
Extra input in buffer
expected = 8, pos = 6
If it is desired to disallow even trailing whitespace characters, "%d %d %d%n"
can be used instead. Note that in order for this to work, the newline character must be removed from buffer[]
so that it is not counted as extra input. One typical way to do this is by using buffer[strcspn(buffer, "\r\n")] = '\0'
:
int main(void)
{
char buffer[BUF_SZ];
int x, y, z;
int pos;
printf("Enter three integers: ");
fflush(stdout);
// get user input
if (fgets(buffer, sizeof buffer, stdin) != NULL) {
// first check: does input match 3 integers?
if (sscanf(buffer, "%d %d %d%n", &x, &y, &z, &pos) != 3) {
puts("Incorrectly formatted input");
} else {
// remove trailing newline character
buffer[strcspn(buffer, "\r\n")] = '\0';
// second check: did sscanf() finish at the end of the buffer?
int expected = strlen(buffer);
if (pos != expected) {
puts("Extra input in buffer");
printf("expected = %d, pos = %d\n", expected, pos);
} else {
// everything OK
printf("You entered: %d, %d, %d\n", x, y, z);
}
}
}
return 0;
}