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

Как прочитать строку с пробелами

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

Строку целиком, вместе с пробелами, читает fgets:

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

int main(void) {
    char name[100];
    if (fgets(name, sizeof(name), stdin) == NULL) {
        return 1;
    }
    name[strcspn(name, "\n")] = '\0';
    printf("Здравствуйте, %s!\n", name);
    return 0;
}
Ввод
Иван Петрович Сидоров
Вывод
Здравствуйте, Иван Петрович Сидоров!

fgets(name, sizeof(name), stdin) читает из stdin (клавиатуры) строку до перевода строки включительно, но не больше sizeof(name) − 1 символов — последнее место остаётся для '\0'. Выйти за границы массива fgets не может. Если ввод кончился, функция возвращает NULL.

Почему scanf("%s") читает только одно слово

Формат %s останавливается на первом пробеле: из «Иван Петрович» в массив попадёт только «Иван», а остальное останется для следующего чтения. Так задумано — %s читает слово. Для строки с пробелами нужен fgets.

Убрать перевод строки

fgets оставляет в конце \n (если строка поместилась целиком). Из-за него ломаются сравнение strcmp(name, "Иван") и вывод — после имени появляется лишний перевод строки. Строка

C
name[strcspn(name, "\n")] = '\0';

ставит конец строки на место первого \n. strcspn возвращает номер первого символа из списка (здесь — \n) или длину строки, если такого символа нет, поэтому запись безопасна в обоих случаях.

fgets после scanf не ждёт ввода

C
scanf("%d", &age);
fgets(name, sizeof(name), stdin);   // сразу получает пустую строку

scanf прочитал число, а перевод строки после него остался непрочитанным. fgets находит его первым и считает, что строка пустая. Перед fgets дочитайте остаток строки:

C
int ch;
while ((ch = getchar()) != '\n' && ch != EOF) {
}

Полный пример и другие «пропуски» ввода — в справке scanf пропускает ввод.

Чтение всех строк до конца

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

int main(void) {
    char line[256];
    int n = 0;
    while (fgets(line, sizeof(line), stdin) != NULL) {
        line[strcspn(line, "\n")] = '\0';
        n++;
        printf("%d: %s\n", n, line);
    }
    return 0;
}
Ввод
первая строка
вторая строка
Вывод
1: первая строка
2: вторая строка

Из файла строки читаются так же — вместо stdin передаётся указатель на открытый файл: fgets(line, sizeof(line), f).

Чего не делать

Функцию gets удалили из языка в стандарте C11: она не знает размера массива, и длинная строка затирает соседнюю память. Свежие компиляторы предупреждают о ней или не собирают программу. Используйте fgets.