可以使用fseek(stdin,1,SEEK_SET)或者rewind(stdin)来清空输入缓冲区,而不用使用不可移植的fflush(stdin)吗?

7
自从我发现fflush(stdin)不是处理输入缓冲区中的换行符问题的可移植方式后,每当我必须使用scanf时,我就会使用以下方法:
while((c = getchar()) != '\n' && c != EOF);

但是今天我偶然发现了这一行话,它来自cplusplus.com on fflush

fflush()...在打开更新文件(即同时打开读写)的情况下,在执行输入操作之前,必须在输出操作后刷新流。可以通过重新定位(fseek、fsetpos、rewind)或显式调用fflush来完成此操作。

事实上,我以前已经多次阅读过这篇文章。所以我想确认是否可以在scanf()之前使用以下任何一个来达到与支持fflush(stdin)相同的目的:

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

PS rewind(stdin) 看起来很安全可靠,可以清空缓冲区,我错了吗?

错误 如果我们在谈论 stdin,那么我应该提到 fseek(stdin,0,SEEK_SET),因为这种情况下不能使用除0或ftell()返回的值以外的任何偏移量。


根据您的引用,“... 输出操作后应刷新流 ...”。您是否期望在stdin上执行输出操作,以需要fflush(stdin)?这似乎很愚蠢!您想要向只读流写入内容?为什么不描述一下您所说的刷新缓冲区是什么,或者您希望fflush(stdin)做什么?您还可以考虑一下fflush根据非C++手册实际执行的操作。毕竟,这是C,而不是C++... - autistic
@undefinedbehaviour 这不是我的引用。这是从http://www.cplusplus.com/reference/cstdio/fflush/中获取的,它涉及到两个I/O流,而不仅仅是特定的`stdin`。我的意思是,当从`stdin`读取时,根据该段落,我们可以通过在其上使用`rewind()`或`fseek()`来刷新它。 - Jugni
stdin仅供阅读打开,不支持更新(既不能读又不能写)。不要混淆这两种模式。该网站通常精度极低,请寻找其他手册网站。我推荐使用opengroup。 - autistic
@undefinedbehaviour 好的,我从来没有说过我打算写入 stdin。我的意思是,如果之前的 Enter 键还有一个换行符,那么为什么我们不能使用 fseek()rewind() 来清除它呢?你是不是想说 stdin 不可寻址?是这样吗? - Jugni
不,我的意思是stdin不可写。fflush会导致数据被写入。点击我第一条评论中的链接,你就会看到。有三种访问模式:读取、写入和更新。你说的“flush it”是什么意思?请定义这个过程,但不要使用“flush”这个词(因为那是无意义的),你会发现即使文件是可寻址的,seek也不能帮助你太多。 - autistic
我猜你的意思是“读取并丢弃一行剩余部分(因为用户可能出现了错误,你想要提示进行更正,或者因为你已经从该行中提取了所需的信息,不再关心其余部分)”。但是寻找或倒回如何帮助你做到这一点呢?看一下while循环中的代码。它如何帮助你读取和丢弃一行的剩余部分?scanf("%*[^\n]"); getchar(); 如何帮助你读取并丢弃一行的剩余部分? - autistic
1个回答

4

这是唯一可用的便携成语:

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

包括这个线程在内的几个线程解释了为什么fseek通常不起作用。出于同样的原因,我怀疑rewind也不会起作用,事实上,手册页面说明它等价于:

(void) fseek(stream, 0L, SEEK_SET)

我看了你给的链接,但似乎有点难以理解。你能否将与这个问题相关的部分简单地概括一下? - Jugni
@Jugni, 这条评论确实很好地解释了这个问题。基本上,流没有被存储在任何地方。如果你想在数据中移动,请将其读入内存。 - Shafik Yaghmour
我的意思是,通常我们使用 fopen() 打开文件时,它会先被读入缓冲区/内存中,因为这样比每次从磁盘读写更快。 - Jugni
@undefinedbehaviour 好的,如果我更正我的问题并使用0作为从SEEK_SET偏移量,为什么寻求不被允许? - Jugni
只要文件是可寻址的,它就会被允许……但它不会做你想要的事情。 - autistic
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接