【问题标题】:plain-C stdin buffer garbage and newline-eaters普通 C 标准输入缓冲区垃圾和换行符
【发布时间】:2023-03-26 06:21:01
【问题描述】:

我有一个关于标准输入缓冲区内容检查的问题。

这行广受赞誉的代码:

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

在发现垃圾时有效地丢弃标准输入缓冲区垃圾。如果缓冲区为空,则程序执行不会越过它。

有没有办法检查标准输入缓冲区中是否有垃圾(无论是由于用户错误、提前输入还是其他原因),并且仅在以防万一的情况下从上面执行“fflush-replacement line”找到垃圾了吗?

我更愿意以编程方式将其全部保留为标准 C 的普通 UNIX 风格,而不必使用特殊的解析工具,没有 yacc、bison、python、ruby、shell 脚本等,没有 Windows API,拜托.

提前致谢!

更新:

我希望这个例子能更多地说明我的问题:

//...
//this line should make sure stdin buffer is free from accidentally typed content
int c; while (( c = getchar()) != '\n' && c != EOF);

//this line won't show in case buffer is already clean
printf("Please enter an arbitrary number of float or symbolic values:\n");

//this line should read the real input user is being asked for
char* p = fgets(text, TEXT_SIZE, stdin);
if(p != NULL)
parse_and_process(text);
//...

当没有意外输入时,就会出现问题。 “垃圾”在这里被认为是在 printf( ) 提示出现时可能留在缓冲区中的任何东西。如果缓冲区已经干净,有没有办法绕过第一行?

【问题讨论】:

  • 引用的 lineof 代码会删除 stdin 中的所有内容,直到读取换行符或 EOF。那么您认为“垃圾”是什么?
  • 请编辑您的问题并添加一个演示问题的示例。
  • IMO,除了仅调用while ((int c = getchar()) != '\n' && c != EOF); 读取数据并检测到它之外,没有可移植的方法来“绕过第一行以防缓冲区已经干净”不以'\n' 结尾。然后stdin 为空,供下一个阅读。
  • 感谢您的评论@chux。不幸的是,除非真的需要修复,否则我不会要求这样做。你提到的所有(1),(2)正是我想要阻止的。我的问题不排除在读取实际用户数据之后清理标准输入。

标签: c unix stdin


【解决方案1】:

这行广受赞誉的代码:

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

有效地处理 丢弃标准输入缓冲区垃圾

没有。这只是读取字符,直到找到换行符或达到 EOF。我不明白你在说什么垃圾。

因此,这样做会消耗掉留在标准输入缓冲区中的换行符。这是刷新缓冲区的方法之一。

【讨论】:

  • 为什么“不”?到底指的是什么?
  • @alk 不知道什么被认为是垃圾,所以我说了代码的实际含义.. 如果换行符被认为是垃圾,那么是 :)
  • 啊.. - 所以你的意思是一个令人困惑的问题应该得到一个令人困惑的答案......? ;->
  • @alk 没有令人困惑的问题需要一个明确的答案,它说明实际的代码行在做什么,其余的留给 OP ..
  • 正如我所说,它可以有效地处理缓冲区中剩余的内容。我只想知道如果标准输入缓冲区为空,如何绕过这条线?希望我现在已经说清楚了。
【解决方案2】:

编辑以回复 OP 评论。

您需要指定什么是垃圾。只有这样,您(或其他任何人)才能确定哪些输入是有效的。

一旦您确定了这一点,您就可以编写一个例程,安静地使用类别为垃圾的用户输入,直到检测到一些非垃圾输入。

Windows(非 Unix)C 编程中使用的 conio.h 标头包含用于控制台输入/输出的函数。 conio.h的一些最常用的函数有clrscrgetchgetchekbhit等。

以下是来自 here 的示例,该示例说明了如何运行一个消耗输入的循环,直到 non-garbage 出现在键盘...(在这种情况下,它被编写为与转义键一起使用,使用 conio 函数的改编,但您可以根据自己的目的对其进行改编)

   do
   {
      ch = _getch();
      ch = toupper( ch );

      if (ch != 27) {
         _cputs( "CHARACTER: " );
         _putch( ch );
         _putch( '\r' );    // Carriage return
         _putch( '\n' );    // Line feed
      }

   } while( ch != 27 ); 

原帖
这不回答 有没有办法检查是否标准输入缓冲区中有垃圾,但它解决了如何确保它清晰...
添加一行向用户明确如何开始,并且由于您的原始代码,这将导致在用户被指示输入其他值之前清除任何垃圾或意外输入的缓冲区...:.. .

    ...
    printf("hit <return> to begin");
    while ( (c = getchar()) != '\n' && c != EOF );
    printf("Please enter an arbitrary number of float or symbolic values:\n");    
    ...

【讨论】:

  • 谢谢,但这正是我希望避免的。它是一个更大的程序的一部分,该程序至少有 50 个类似的交互情况(非常频繁地使用),我不能通过显示你真诚地建议给我的句子来开始每一个。
  • 感谢您的回复。垃圾while ( (c = getchar()) != '\n' &amp;&amp; c != EOF ); 被执行时留在缓冲区中的任何东西。在用户有意识地按照printf( ) 声明行事之前,没有“非垃圾”。问题是干净的缓冲区会导致 while( ) 挂起,直到满足 '\n' 条件。