Как прочитать строку с пробелами
Строку целиком, вместе с пробелами, читает fgets:
#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, "Иван") и вывод — после имени появляется лишний перевод строки. Строка
name[strcspn(name, "\n")] = '\0';ставит конец строки на место первого \n. strcspn возвращает номер первого символа из списка (здесь — \n) или длину строки, если такого символа нет, поэтому запись безопасна в обоих случаях.
fgets после scanf не ждёт ввода
scanf("%d", &age);
fgets(name, sizeof(name), stdin); // сразу получает пустую строкуscanf прочитал число, а перевод строки после него остался непрочитанным. fgets находит его первым и считает, что строка пустая. Перед fgets дочитайте остаток строки:
int ch;
while ((ch = getchar()) != '\n' && ch != EOF) {
}Полный пример и другие «пропуски» ввода — в справке scanf пропускает ввод.
Чтение всех строк до конца
#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.
scanf("%[^\n]", s)читает до перевода строки, но без числа в формате так же опасен, какgets. Если пользоваться им, то с ограничением:scanf("%99[^\n]", s)для массива из 100 символов.- Строка длиннее массива.
fgetsпрочитает только часть, а остаток достанется следующему вызову. Признак: в прочитанной строке нет\n. Берите массив с запасом. getline— удобная функция, которая сама выделяет память под строку любой длины. Но это не стандарт C, а POSIX (общий стандарт Unix-подобных систем): в Linux и macOS она есть, а в Visual Studio её нет, поэтому программа с ней собирается не везде.