читать char из консоли

Я пишу консольное приложение, которое выполняет несколько scanf для int, а после этого я выполняю getchar:

int x,y;
char c;
printf("x:\n");
scanf("%d",&x);
printf("y:\n");
scanf("%d",&y);
c = getchar();

в результате этого я получаю c = '\n', несмотря на ввод:

1
2
a

Как можно решить эту проблему?


person Yakov    schedule 13.01.2012    source источник
comment
getchar() возвращает int, а не char.   -  person unwind    schedule 13.01.2012
comment
@unwind — возвращает следующий символ из стандартного ввода (stdin).-ascii для char   -  person Yakov    schedule 13.01.2012


Ответы (5)


Это связано с тем, что scanf оставляет новую строку, которую вы вводите во входном потоке. Пытаться

do
    c = getchar();
while (isspace(c));

вместо

c = getchar();
person Fred Foo    schedule 13.01.2012

Вызовите fflush(stdin); после scanf, чтобы отбросить все ненужные символы (например, \r \n) из входного буфера, которые были оставлены scanf.

Редактировать: поскольку ребята в комментариях упоминали, что решение fflush может иметь проблемы с переносимостью, так что вот мое второе предложение. Не используйте scanf вообще и сделайте эту работу, используя комбинацию fgets и sscanf. Это гораздо более безопасный и простой подход, поскольку позволяет обрабатывать неправильные входные ситуации.

int x,y;
char c;
char buffer[80];

printf("x:\n");
if (NULL == fgets(buffer, 80, stdin) || 1 != sscanf(buffer, "%d", &x))
{
    printf("wrong input");
}
printf("y:\n");
if (NULL == fgets(buffer, 80, stdin) || 1 != sscanf(buffer, "%d", &y))
{
    printf("wrong input");
}
c = getchar();
person Zuljin    schedule 13.01.2012
comment
-1 fflush(stdin) не определено. Даже Microsoft/MSDN (кто определяет такую ​​конструкцию) говорит (хотя и в скрытом месте), что это расширение: // fflush во входном потоке является расширением стандарта C. - person pmg; 13.01.2012
comment
@pmg: Верно! (Даже я склонен указывать на это время от времени). Это довольно часто встречается на SO., но это работает, поддерживается MSDN (вы указали ссылку на страницу) и Linux... "For input streams, fflush() discards any buffered data that has been fetched from the underlying file, but has not been consumed by the application...The standards do not specify the behavior for input streams. Most other implementations behave the same as Linux. "...так насколько плохо его использовать в коде? - person another.anon.coward; 13.01.2012
comment
Текст на странице POSIX.1-2008 немного отличается: приложение вообще не упоминается. Мне совсем не нравится это описание POSIX.1-2008. Линукса и винды и POSIX (со всеми оговорками) мне недостаточно, чтобы называть переносимым. - person pmg; 13.01.2012
comment
@anoner.anon.coward: также, почему вы добровольно ограничиваете себя Linux, Windows и POSIX (со всеми оговорками), когда вы можете очень легко достичь гораздо большего количества реализаций? - person pmg; 13.01.2012
comment
@pmg: Вы определенно правы насчет переносимости! Но если бы я ограничил этот вызов в своей реализации на платформе, которая поддерживает, скажем, Linux, я вполне мог бы использовать это с макросом, например #ifdef LINUX (возможно, что-то вроде использования расширений C, скажем, gcc, когда это возможно). Как вы упомянули, лучше придерживаться стандартов. Спасибо за ваши идеи! - person another.anon.coward; 14.01.2012
comment
отменил -1 ... даже условие Йоды с ... и почему в вашем коде есть c = getchar();? - person pmg; 14.01.2012
comment
@pmg, так каков правильный кроссплатформенный способ отбросить все ненужные символы, оставшиеся после scanf или gets? - person Unicorn; 12.02.2015
comment
@Romeno: правильный кроссплатформенный способ чтения пользовательского ввода - это fgets(). fgets() не оставляет ненужных символов во входном потоке. - person pmg; 13.02.2015
comment
@pmg, это неправда. MSVC10 fgets() do оставляет ненужные символы во входном потоке. Более того, он не возвращает NULL, если вы ввели более n-1 символов. Он просто зажимает входной поток до n-1. Далее fgets продолжит потреблять введенные символы. - person Unicorn; 14.02.2015

Вы можете использовать функцию fflush для очистки всего, что осталось в буфере в результате предыдущих вводов командной строки:

fflush(stdin);
person ETFovac    schedule 24.06.2014
comment
fflush(stdin) вызывает неопределенное поведение в соответствии со стандартом C, хотя оно четко определено в некоторых системах (реализациях), но его лучше избегать, чтобы улучшить переносимость. - person Spikatrix; 21.10.2015

Способ очистить любое пространство перед желаемым символом и просто игнорировать оставшиеся символы:

do {
    c = getchar();
} while (isspace(c));
while (getchar() != '\n');
person Josué    schedule 09.07.2013

Для начала scanf следует читать scanf("%d\n", &x); или y. Это должно делать свое дело.

man scanf

person Ed Heal    schedule 13.01.2012
comment
Он неt work :after I enter 1 it doesnне записывает y: (см. обновленный пример), а ждет второго числа и только после него записывает y: - person Yakov; 13.01.2012