Можно ли использовать fseek(stdin,1,SEEK_SET) или rewind(stdin) для очистки входного буфера вместо непереносимого fflush(stdin)?

Поскольку я обнаружил, что fflush(stdin) не является переносимым способом решения знакомой проблемы "новой строки, скрывающейся во входном буфере", я использовал следующее, когда должен использовать scanf:

while((c = getchar()) != '\n' && c != EOF);

Но сегодня я наткнулся на эту строку, которую я заметил на cplusplus.com на fflush< /а>:

fflush()... в файлах, открытых для обновления (т. е. открытых как для чтения, так и для записи), поток должен очищаться после операции вывода перед выполнением операции ввода. Это можно сделать либо перепозиционированием (fseek, fsetpos, перемотка назад), либо явным вызовом fflush

На самом деле, я читал это раньше много раз. Поэтому я хочу подтвердить, могу ли я просто использовать что-либо из следующего перед scanf() для той же цели, что и fflush(stdin), когда он поддерживается:

fseek(stdin,1,SEEK_SET);
rewind(stdin);

PS rewind(stdin) кажется довольно безопасным и пригодным для очистки буфера, я ошибаюсь?

Ошибка Я должен был упомянуть fseek(stdin,0,SEEK_SET), если мы говорим о stdin, поскольку в этом случае мы не можем использовать никакое смещение, кроме 0 или сдвига, возвращаемого ftell().


person Jugni    schedule 21.05.2013    source источник
comment
Из вашей цитаты... поток должен очищаться после операции вывода .... Ожидаете ли вы выполнять операции вывода над stdin, чтобы потребовать fflush(stdin)? Это кажется глупым! Вы хотите записывать в поток только для чтения?! Почему бы вам не описать, что вы подразумеваете под очисткой буфера или что вы хотите, чтобы fflush(stdin) делал? Вы также можете рассмотреть, что на самом деле делает fflush согласно руководству, отличному от C++< /а>. Ведь это С, а не С++...   -  person autistic    schedule 21.05.2013
comment
@undefinedbehaviour Это не моя цитата. Она взята с cplusplus.com/reference/cstdio/fflush и это говорит об обоих потоках ввода-вывода, а не о stdin в частности. Я имел в виду, что при чтении из stdin, согласно этому абзацу, мы могли бы очистить его, используя для него rewind() или fseek().   -  person Jugni    schedule 21.05.2013
comment
stdin открыт только для чтения, а не для обновления (как для чтения, так и для записи). Не путайте эти два режима. Это не редкость для этого сайта, чтобы быть грубо неточным. Найдите другой сайт с руководствами. Я рекомендую открытую группу.   -  person autistic    schedule 21.05.2013
comment
@undefinedbehaviour Ну, я никогда не говорил, что собираюсь писать в stdin. Я имею в виду, что если от предыдущей клавиши Enter осталась новая строка, то почему мы не можем использовать для нее fseek() и rewind()( чтобы сбросить его). Вы хотите сказать, что stdin недоступен для поиска? Это так?   -  person Jugni    schedule 21.05.2013
comment
Нет. Я имею в виду, что stdin недоступен для записи. fflush вызывает запись данных. Нажмите на ссылку в моем первом комментарии, и вы увидите это. Существует три режима доступа: открыть для чтения, открыть для записи и открыть для обновления. Что вы подразумеваете под сбросить? Определите этот процесс, не используя слово flush (потому что это тарабарщина), и вы увидите, что поиск не может вам сильно помочь, даже если файл доступен для поиска.   -  person autistic    schedule 22.05.2013
comment
Я предполагаю, что вы имеете в виду прочитать и отбросить оставшуюся часть строки (потому что пользователь допустил ошибку, и вы хотите запросить исправления, или потому что вы уже извлекли нужную вам информацию из этой строки, и вам все равно на остальное из него). Как поиск или перемотка помогают вам в этом? Посмотрите код в цикле while. Как это поможет вам прочитать и отбросить оставшуюся часть строки? Как scanf("%*[^\n]"); getchar(); может помочь вам прочитать и отбросить остаток строки?   -  person autistic    schedule 22.05.2013


Ответы (1)


Это единственная портативная идиома для использования:

while((c = getchar()) != '\n' && c != EOF);

Несколько тем, включая эту, объясняют, почему feesk обычно не работает. почти по тем же причинам я сомневаюсь, что rewind тоже будет работать, на самом деле на странице руководства говорится, что это эквивалентно:

(void) fseek(stream, 0L, SEEK_SET)
person Shafik Yaghmour    schedule 21.05.2013
comment
Я прочитал ту ссылку, которую вы дали. Но кажется, что это немного сложно понять. Не могли бы вы изложить часть этой ссылки, относящуюся к этому вопросу, в несколько простых строк? - person Jugni; 21.05.2013
comment
@Jugni Этот комментарий действительно хорошо объясняет stackoverflow.com/questions/4917801/, в основном поток нигде не хранится. Если вы хотите просмотреть данные, прочитайте их в памяти. - person Shafik Yaghmour; 21.05.2013
comment
Но я читал, что поток буферизуется по умолчанию. Я почти уверен, что stdin и stdout буферизуются. Как и все потоки, открытые с помощью fopen() - person Jugni; 21.05.2013
comment
Я имею в виду, что обычно, когда мы открываем файл с помощью fopen(), он сначала считывается в буфер/память, так как это быстрее, чем каждый раз читать запись с диска. - person Jugni; 21.05.2013
comment
@Jugni Нет. Стандарт C11 говорит в отношении fopen При открытии поток полностью буферизуется тогда и только тогда, когда можно определить, что он не относится к интерактивному устройству. ... и в отношении fseek Для текстового потока либо смещение должно быть равно нулю, либо смещение должно быть значением, возвращаемым более ранним успешным вызовом функции ftell в потоке, связанном с тем же файлом, и значением, равным SEEK_SET. . .. поэтому, даже если у вас есть stdin с возможностью поиска (например, он был передан из файла), это может быть текстовый поток (например, в Windows), и вам не следует искать, как в вашем вопросе... - person autistic; 21.05.2013
comment
@undefinedbehaviour Итак, если я исправлю свой вопрос и использую 0 в качестве смещения от SEEK_SET, почему поиск не будет разрешен? - person Jugni; 21.05.2013
comment
При условии, что файл доступен для поиска, он будет разрешен... но он не будет делать то, что вы хотите. - person autistic; 22.05.2013