Стоит ли вообще заглядывать в буфер stdin?
Мы знаем, что stdin
по умолчанию является буферизованным входом; доказательство этого заключается в использовании любого из механизмов, которые "оставляют данные" на stdin
, например scanf()
:
int main()
{
char c[10] = {'\0'};
scanf("%9s", c);
printf("%s, and left is: %d\n", c, getchar());
return 0;
}
./a.out
привет
привет, а слева - 10
10
является новой линией, конечно...
Мне всегда было любопытно, есть ли способ "заглянуть" в буфер stdin
, не удаляя все, что может там проживать?
ИЗМЕНИТЬ
Лучший пример может быть:
scanf("%9[^.]", c);
При вводе "at.ct" теперь у меня есть "данные" (ct\n
), оставшиеся на stdin
, а не только символ новой строки.
Ответы
Ответ 1
В переносном режиме вы можете получить следующий символ во входном потоке с помощью getchar()
, а затем вернуть его с помощью ungetc()
, что приведет к состоянию, как если бы символ не был удален из потока.
Функция ungetc
возвращает символ, указанный c
(преобразованный в unsigned char
) обратно на входной поток, на который указывает поток. Отточенные символы будут возвращены последующими чтениями в этом потоке в обратном порядке их нажатия.
Стандарт гарантирован только одному символу pushback, но обычно вы можете нажать еще больше.
Как упоминалось в других ответах, соответственно. комментарии там, на практике, вы почти наверняка заглядываете в буфер, если вы предоставляете свой собственный буфер с setvbuf
, хотя это не без проблем:
Если buf
не является нулевым указателем, массив, на который он указывает, может использоваться вместо буфера, выделенного функцией setvbuf
что оставляет возможность того, что предоставленный буфер вообще не может быть использован.
Содержимое массива в любое время неопределенно.
это означает, что у вас нет гарантии, что содержимое буфера отражает фактический ввод (и это делает использование поведения буфера undefined, если оно имеет автоматическую продолжительность хранения, если мы придирчивы).
Однако на практике основной проблемой было бы выяснить, где в буфере начинается еще не потребленная часть буферизованного ввода и где она заканчивается.
Ответ 2
Вы можете установить свой собственный буфер с setvbuf
на stdin и заглянуть туда, когда захотите.
Ответ 3
Если вы хотите посмотреть на буфер stdin
, не изменяя его, вы можете сказать ему использовать другой буфер с setbuf
, используя массив, к которому вы можете получить доступ:
char buffer[BUFSIZ];
if (setbuf(stdin, buffer) != 0)
// error
getchar();
printf("%15s\n", buffer);
Это позволит вам увидеть что-то большее, чем ungetc
, но я не думаю, что вы можете пойти дальше портативным способом.
На самом деле это законно, но неверно для стандарта, цитируя его о setvbuf
(setbuf
имеет такое же поведение):
Содержимое массива в любое время неопределенно.
Итак, это не то, что вам нужно, если вы ищете полную переносимость и стандартную совместимость, но я не могу себе представить, почему буфер не должен содержать ожидаемого. Однако, похоже, он работает на моем компьютере.
Помните, что вам необходимо предоставить массив не менее BUFSIZ
символов до setbuf
, и вы не должны выполнять никаких операций ввода-вывода в потоке перед ним. Если вам нужна большая гибкость, посмотрите setvbuf
.