У меня есть такая программа:
int main(int argc, char *argv[])
{
int a, b;
char c1, c2;
printf("Enter something: ");
scanf("%d",&a); // line 1
printf("Enter other something: ");
scanf("%d", &b); // line 2
printf("Enter a char: ");
scanf("%c",&c1); // line 3
printf("Enter another char: ");
scanf("%c", &c2); // line 4
printf("Done"); // line 5
system("PAUSE");
return 0;
}
Как я читал в книге C, автор говорит, что scanf()
оставил символ новой строки в буфере, поэтому программа не останавливается на строке 4 для ввода данных пользователем, скорее она сохраняет символ новой строки в c2 и переходит к строка 5.
Это правильно?
Однако происходит ли это только с char
типами данных? Потому что я не видел этой проблемы с int
типами данных, как в строке 1, 2, 3. Верно?
fflush(stdin)
использовать его перед вызовомscanf()
для одного символа. Пожалуйста, прочтите Использованиеfflush(stdin)
для обсуждения плюсов и минусов, а также альтернатив этому методу (который более или менее работает в Windows и не работает в большинстве других мест).Ответы:
В
scanf()
функции пропускает ведущие пробелы автоматически , прежде чем пытаться разобрать , кроме символов преобразования. Форматы символов (в первую очередь%c
; также наборы сканирования%[…]
- и%n
) являются исключением; они не пропускают пробелы.Используйте
" %c"
с пробелом в начале, чтобы пропустить необязательный пробел. Не используйте завершающий пробел вscanf()
строке формата.Обратите внимание, что это по-прежнему не использует никаких конечных пробелов, оставшихся во входном потоке, даже до конца строки, поэтому остерегайтесь этого, если вы также используете
getchar()
илиfgets()
в том же входном потоке. Мы просто заставляем scanf пропускать пробелы перед преобразованиями, как это делается для%d
и других несимвольных преобразований.Обратите внимание, что «директивы» без пробелов (для использования терминологии POSIX scanf ), отличные от преобразований, такие как буквальный текст в
scanf("order = %d", &order);
, также не пропускают пробелы. Литералorder
должен соответствовать следующему символу для чтения.Так что вы, вероятно, захотите
" order = %d"
туда, если хотите пропустить новую строку из предыдущей строки, но все же требуете буквальное совпадение с фиксированной строкой, как этот вопрос .источник
%c
,%n
,%[]
Являются 3 специфицированные ожидания , которые не потребляют ведущие пробелы.scanf()
строке формата иscanf()
запрос дважды на ввод, хотя я ожидаю, что он запросит только один раз для обсуждения конечных пробелов в строках формата. Это плохая идея - поразительно плохая, если вы ожидаете человеческого взаимодействия, и плохая для взаимодействия с программой.Используйте
scanf(" %c", &c2);
. Это решит вашу проблему.источник
Другой вариант (который я получил отсюда ) - прочитать и отбросить новую строку с помощью параметра присваивания-подавления . Для этого мы просто устанавливаем формат для чтения символа со звездочкой между
%
иc
:scanf("%d%*c",&a); // line 1 scanf("%c%*c",&c1); // line 3
scanf
затем прочитает следующий символ (то есть новую строку), но не назначит его никакому указателю.В конце концов, однако, я бы поддержал последний вариант FAQ :
источник
a
затем пробел, а затем новую строку, подавленное преобразование символов считывает пробел и по-прежнему оставляет новую строку. Если пользователь набирает,supercalifragilisticexpialidocious
когда вы ожидаетеa
, у вас есть много лишних символов, с которыми нужно иметь дело. Вы также никогда не можете сказать, успешна ли завершающая подавленная конверсия - они не учитываются в возврате изscanf()
.Используйте
getchar()
перед вызовом второгоscanf()
.scanf("%c", &c1); getchar(); // <== remove newline scanf("%c", &c2);
источник
int c; while ((c = getchar()) != EOF && c != '\n') ;
(записывается на трех строках, когда не в комментарии). Часто этого бывает достаточно; это не надежно (и вы должны помнить, что дураки очень умны в том, чтобы ломать вещи).