这是刷新 C 输入流的正确方法吗?

Is this the proper way to flush the C input stream?

好吧,我在 google 和此处搜索了很多有关如何正确刷新输入流的信息。我听到的只是关于输入流的 fflush() 是如何未定义的混合争论,有些人说就那样做,而其他人只是说不要这样做,我没有找到一个明确的 efficient/proper 这样做的方式,大多数人都同意..我在编程方面很新,所以我还不知道该语言的所有 syntax/tricks,所以我的问题是哪种方式最多 efficient/proper清除C输入流的解决方案??

  1. 在尝试接收更多输入之前使用 getchar() 两次?

  2. 直接在输入上使用fflush()函数?或

  3. 这就是我认为我应该做的。

    void clearInputBuf(void);  
    void clearInputBuf(void) 
    { 
          int garbageCollector; 
          while ((garbageCollector = getchar()) != '\n' && garbageCollector != EOF) 
          {}
    }
    

因此,每当我需要读取新的 scanf() 或使用 getchar() 来暂停程序时,我只需调用 clearInputBuf..那么,三种解决方案中最好的方法是什么?更好的选择?

All I hear is mixed arguments about how fflush() is undefined for the input stream

没错。不要使用 fflush() 刷新输入流。

(A) 适用于在输入流中留下单个字符的简单情况(例如 scanf() 留下换行符)。

(B) 不要使用。它在某些平台上定义。但不要依赖标准调用 未定义的行为.

(C) 显然是 3 个选项中最好的,因为它可以 "flush" 输入流中任意数量的字符。

但如果您阅读 (例如使用 fgets()),您可能就不太需要清除输入流。

原来是平台相关的。

fflush() 不能将输入流作为参数,因为根据 c 标准,它是未定义的行为,因为该行为未在任何地方定义。

  • 在 Windows 上,fflush() 有一个定义的行为,它会做你需要它做的事情。

  • 在 Linux 上,还有 fpurge(3) 也可以做你想做的事。

最好的方法是简单地循环读取所有字符,直到

  1. 找到换行符。
  2. EOFgetchar() 返回。

喜欢你的 clearInputBuf() 函数。

请注意,刷新输出流意味着将所有未写入的数据写入流,即仍在缓冲区中等待刷新的数据。但是从流中读取所有未读字节,并没有相同的含义。

这就是 fflush() 输入流没有意义的原因。另一方面 fpurge() 是专门为此设计的,它的名字是更好的选择,因为你想清除输入流并重新开始。问题是,它不是标准函数。

阅读 fpurge(3) 应该阐明为什么 fflush(stdin) 是未定义的行为,以及为什么像 Windows 上的实现没有意义,因为它使 fflush() 行为不同的输入不同。这就像让 c 符合 PHP.

这取决于您如何看待"flushing an input stream"。

对于输出流,刷新操作确保所有写入流但在内存中缓冲的数据都已刷新到底层文件系统文件。这是一个定义非常明确的操作。

对于输入流,对于刷新流应该做什么没有明确定义的操作。我会说这没有任何意义。

C 标准库的某些实现将输入流的 "flush" 的含义重新定义为 "clear the rest of the current line which has not been read yet"。但这完全是任意的,其他实现选择什么也不做。

从 C11 开始,这种差异已得到纠正,标准现在明确指出 fflush() 函数不适用于输入流,正是因为它没有意义,我们不希望每个运行时库供应商以他们喜欢的任何方式实施它。

因此,请务必按照您的方式继续执行您的 clearInputBuf() 函数,但不要将其视为 "flushing the input stream"。没有这样的东西。

问题比看起来更微妙:

  • 在具有复杂终端设备的系统上,例如 unix 和 OS/X,来自终端的输入在 2 个不同的级别进行缓冲:系统终端使用缓冲区来处理行编辑,来自只需使用退格键更正输入即可使用光标和控制键进行全行编辑。这称为 cooked 模式。在输入回车键或输入文件结束键组合之前,系统会缓冲一整行输入。

  • FILE 函数执行它们自己的缓冲,对于与终端关联的流,默认情况下是行缓冲。默认情况下,缓冲区大小设置为 BUFSIZ,当缓冲内容被消耗时,系统会请求字节。对于大多数请求,整行将从系统读取到流缓冲区中,但在某些情况下,例如当缓冲区已满时,当 scanf() returns。这就是丢弃流缓冲区的内容可能并不总是足够的原因。

刷新输入缓冲区可能意味着不同的事情:

  • 丢弃额外的输入,包括换行符,这些输入是用户响应 getchar()fgets()scanf() 等输入请求而输入的. flushing这个输入的需要在scanf()的情况下尤为明显,因为大多数格式行不会导致换行被消耗。

  • 放弃任何待处理的输入并等待用户按下键。

你可以为第一种情况实现可移植的 fluch 函数:

int flush_stream(FILE *fp) {
    int c;
    while ((c = getc(fp)) != EOF && c != '\n')
        continue;
    return c;
}

这正是您的 clearInputBuf() 函数为 stdin 所做的。

对于第二种情况,没有可移植的解决方案,系统特定的方法很重要。