Семейство функций scanf()
возвращает количество выполненных успешных назначений.Если код ожидает три элемента ввода, то из значения, возвращенного одним sscanf()
, невозможно определить, были ли предоставлены три или более элементов ввода.
Функции scanf()
работают, читая символ, пытаясьсопоставьте этот символ, сделав присваивание, если это применимо, затем перейдите к следующему символу или вернитесь из вызова функции.Существует спецификатор преобразования %n
, в котором хранится количество символов, прочитанных в этом процессе (без увеличения количества прочитанных символов).Этот спецификатор преобразования может быть использован для определения того, был ли введен исчерпанный ввод при вызове sscanf()
.
. Приведенный ниже код демонстрирует.Строки ввода, собранные fgets()
, содержат символ новой строки, если только ввод не слишком велик для размещения в массиве буферов.Здесь buffer[]
достаточно большой, чтобы хранить входные данные разумного размера, но более надежный код будет обрабатывать слишком большие входные данные более осторожно.Когда sscanf()
сканирует входную строку, каждый символ читается по очереди, пока не произойдет неудачное совпадение или не будет достигнут конец строки, поэтому ожидаемое после сопоставления "%d %d %d %n"
число символов чтения совпадает с длиной вводастрока, включая любые завершающие пробельные символы.
#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;
}
Примеры взаимодействий:
>$ ./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
Если необходимо запретить даже конечные пробельные символы символы, "%d %d %d%n"
можетиспользоваться вместоОбратите внимание, что для того, чтобы это работало, символ новой строки должен быть удален из buffer[]
, чтобы он не считался дополнительным вводом.Один из типичных способов сделать это - использовать 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;
}