Глиф Учебники

scanf пропускает ввод: пробел перед %c

Справочник · C · 1 минута чтения

Чаще всего «пропуск» случается при чтении символа после числа. Решение — пробел перед %c:

C
#include <stdio.h>

int main(void) {
    int n;
    char c;
    scanf("%d", &n);
    scanf(" %c", &c);
    printf("n = %d, c = %c\n", n, c);
    return 0;
}
Ввод
5
y
Вывод
n = 5, c = y

Если ввода не ждёт fgets после scanf или scanf зацикливается на буквах — сразу переходите к разделам fgets после scanf и scanf зациклился.

Почему так происходит

Когда вы набираете 5 и нажимаете Enter, программа получает два символа: 5 и перевод строки \n. scanf("%d") забирает 5, а \n остаётся ждать следующего чтения. Формат %c читает любой символ, в том числе \n, — поэтому scanf("%c", &c) сразу получает перевод строки и не ждёт ввода. Видно, что попало в c, если вывести код символа:

C
#include <stdio.h>

int main(void) {
    int n;
    char c;
    scanf("%d", &n);
    scanf("%c", &c);
    printf("Код символа в c: %d\n", c);
    return 0;
}
Ввод
5
y
Вывод
Код символа в c: 10

10 — код перевода строки. Пробел в формате " %c" означает «пропустить все пробелы, табуляции и переводы строк», и %c получает первый настоящий символ.

Числовые форматы (%d, %lf) и %s пробелы и переводы строк перед значением пропускают сами, поэтому scanf("%d", …) после scanf("%d", …) работает без пробела.

fgets после scanf получает пустую строку

Та же причина: fgets читает до \n и находит его сразу. Перед fgets дочитайте остаток строки:

C
#include <stdio.h>
#include <string.h>

int main(void) {
    int age;
    char name[100];
    scanf("%d", &age);
    int ch;
    while ((ch = getchar()) != '\n' && ch != EOF) {
    }
    fgets(name, sizeof(name), stdin);
    name[strcspn(name, "\n")] = '\0';
    printf("%s, %d лет\n", name, age);
    return 0;
}
Ввод
17
Анна Петрова
Вывод
Анна Петрова, 17 лет

Цикл с getchar() выбрасывает всё, что осталось в строке после числа, вместе с \n. Переменная ch — int, а не char: так её можно сравнить с EOF.

Не используйте fflush(stdin): по стандарту C fflush — только для вывода, а для ввода результат не определён. В старых учебниках этот приём встречается, потому что некоторые компиляторы для Windows так очищали ввод, но полагаться на это нельзя.

scanf зациклился

Если вместо числа ввести буквы, scanf("%d") ничего не прочитает, вернёт 0 и оставит буквы на месте. Цикл while (…) scanf("%d", &x); будет снова и снова натыкаться на те же буквы. Поэтому результат scanf проверяют, а при ошибке выбрасывают остаток строки:

C
#include <stdio.h>

int main(void) {
    int x;
    while (scanf("%d", &x) != 1) {
        int ch;
        while ((ch = getchar()) != '\n' && ch != EOF) {
        }
        if (ch == EOF) {
            return 1;
        }
        printf("Это не число, попробуйте снова\n");
    }
    printf("Принято: %d\n", x);
    return 0;
}
Ввод
abc
42
Вывод
Это не число, попробуйте снова
Принято: 42

Если ввод кончился совсем (EOF), программа завершается, а не крутится вечно.