Чтение новой строки с предыдущего ввода при чтении с клавиатуры с помощью scanf()

Это должно было быть очень простым, но мне трудно читать последовательные входы с клавиатуры.

Здесь код:

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

int main()
{
    char string[200];
    char character;
    printf ("write something: ");
    scanf ("%s", string);
    printf ("%s", string);
    printf ("\nwrite a character: ");
    scanf ("%c", &character);
    printf ("\nCharacter %c  Correspondent number: %d\n", character, character);

    return 0;
}

Что происходит

Когда я ввожу строку (например, компьютер), программа считывает новую строку ('\n') и помещает ее в character. Вот как выглядит экран:

 write something: computer
 computer
 Character:
    Correspondent number: 10

Кроме того, программа не работает для строк с несколькими словами. Как я мог преодолеть эти проблемы?

Ответ 1

Сначала scanf прочитайте введенную строку и оставите \n во входном буфере. Следующий вызов scanf читайте, что \n и сохраните его на character.
Попробуйте это

scanf (" %c", &characte);   
     // ^A space before %c in scanf can skip any number of white space characters. 

Программа не будет работать для строк более одного символа, потому что scanf перестает читать, как только найдет символ пробела. Вместо этого можно использовать fgets

 fgets(string, 200, stdin);

Ответ 2

Первая проблема OP обычно решается путем добавления пробела в формат. Это займет пробел, включая предыдущую строку '\n'.

// scanf("%c", &character);
scanf(" %c", &character);

Кроме того, программа не работает для строк с несколькими словами. Как я мог преодолеть эти проблемы?

Для второго вопроса давайте перейдем к более четкому пониманию "строки" и того, что "%s" делает.

Строка представляет собой непрерывную последовательность символов, заканчивающихся и включающих первый нулевой символ. 7.1.1 1

OP не вводит строку, хотя "Я ввожу строку (например, компьютер)". OP вводит строку текста. 8 символов "компьютер", за которым следует Enter. Здесь нет "нулевого символа". Вместо этого 9 char "computer\n".

"%s" в scanf("%s", string); делает 3 вещи:

1) Сканирование, но не сохранение какого-либо ведущего белого пространства.

2) Сканируйте и сохраните в string любое количество небелого пространства.

3) Прекратить сканирование при достижении пробела или EOF. Это char, но обратно в stdin. A '\0' добавляется к string, делая этот массив char строкой C.

Чтобы прочитать строку, включая пробелы, не используйте scanf("%s",.... Рассмотрим fgets().

fgets(string, sizeof string, stdin);
// remove potential trailing \r\n as needed
string[strcspn(string, "\n")] = 0;

Смешивание scanf() и fgets() является проблемой, поскольку вызовы типа scanf("%s", string); fgets(...) оставляют '\n' в stdin для fgets() для чтения как строку, состоящую только из "\n". Рекомендуйте вместо этого читать все пользовательские данные с помощью fgets() (или getline() on * nix system). Затем проанализируйте прочитанную строку.

fgets(string, sizeof string, stdin);
scanf(string, "%c", &character);

Если код должен пользователь scanf() читать ввод пользователя, включая пробелы:

scanf("%*[\n]"); // read any number of \n and not save.
// Read up to 199 `char`, none of which are \n
if (scanf("%199[^\n]", string) != 1) Handle_EOF();

Наконец, код должен использовать проверку ошибок и ограничения ширины ввода. Проверьте возвращаемые значения всех входных функций.

Ответ 3

То, что вы видите, - это правильное поведение функций, которые вы вызываете:

  • scanf будет читать одно слово из ввода и оставить указатель ввода сразу после прочитанного им слова. Если вы наберете computer<RETURN>, следующий символ, который нужно прочитать, - это новая строка.

  • Чтобы прочитать целую строку, включая окончательную новую строку, используйте fgets. Внимательно прочитайте документацию: fgets возвращает строку, содержащую последнюю прочитанную новую строку. (gets, который не должен использоваться в любом случае по ряду причин, читает и отбрасывает окончательную новую строку.)

Я должен добавить, что, хотя scanf имеет свои применения, использование его в интерактивном режиме приводит к очень запутанному поведению, как я думаю, вы обнаружили. Даже в тех случаях, когда вы хотите читать слово за словом, используйте другой метод, если предполагаемое использование является интерактивным.

Ответ 4

Вы можете использовать %*c:

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

int main()
{
    char string[200];
    char character;
    printf ("write something: ");
    scanf ("%s%*c", string);
    printf ("%s", string);
    printf ("\nwrite a character: ");
    scanf ("%c%*c", &character);
    printf ("\nCharacter %c  Correspondent number: %d\n", character, character);

    return 0;
}

%*c будет принимать и игнорировать новую строку или любые пробелы

Ответ 5

Вы также положите getchar() после строки scanf. Он выполнит эту задачу:)

Ответ 6

Потоки необходимо очистить. При выполнении последовательных входов стандартный поток ввода, stdin, буферирует каждое нажатие клавиши на клавиатуре. Итак, когда вы набрали "компьютер" и нажали клавишу ввода, входной поток также поглотил линию перевода, хотя для string была назначена только строка "компьютер". Следовательно, когда вы сканировали для символа позже, уже загруженный новый символ линии был тем, который был отсканирован и присвоен character.

Также потоки stdout необходимо очистить. Рассмотрим это:

...
printf("foo");
while(1)
{}
...

Если кто-то пытается выполнить что-то подобное, на консоли ничего не отображается. Система буферизует поток stdout, стандартный выходной поток, не подозревая о том, что он будет сталкиваться с бесконечным циклом, и если это произойдет, никогда не будет возможности выгрузить поток на консоль.

По-видимому, аналогично, когда scanf блокирует программу и ждет на stdin, стандартный поток ввода, он влияет на другие потоки, которые буферизуются. В любом случае, как бы то ни было, лучше всего правильно очистить потоки, если все начнет рушиться.

Следующие изменения вашего кода, похоже, создают желаемый вывод

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

int main()
{
char string[200];
char character;

printf ("write something: ");

fflush(stdout);

scanf ("%s", string);

fflush(stdin);

printf ("%s", string);
printf ("\nwrite a character: ");

fflush(stdout);

scanf ("%c", &character);
printf ("\nCharacter %c  Correspondent number: %d\n", character, character);

return 0;
} 

Вывод:
написать что-нибудь: компьютер
компьютер
напишите символ: a

Символ a Корреспондентский номер: 97