当C中的stdin可能为空时清空,也可能不为空

时间:2014-02-11 08:31:56

标签: c stdin

我是一名编程学生,正在寻找摆脱可能在stdin中闲逛的角色的方法。我尝试过一种以各种形式给出的技术,你可以这样做:

void clearStdIn(void) 
{
    char c;
    while((c = getchar()) != '\n' && c != EOF)
        /* discard */ ;
}

问题似乎是如果stdin中没有任何内容开始,则此函数会等待用户在控制流可以继续之前按Enter键。我该怎么办?

3 个答案:

答案 0 :(得分:1)

可以不受阻塞地刷新输入流(以便携方式),如下所示:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

int flush_inputstream(int fd)
{
  int result = 0;

  int flags = fcntl(fd, F_GETFL);
  if (-1 == flags)
  {
    perror("fcntl() failed getting flags");

    result = -1;
    goto lblExit;
  }

  if (!(flags & O_NONBLOCK)) /* If stream isn't non-blocking */
  {                          /* set it to be non-blocking. */
    result = fcntl(fd, F_SETFL, O_NONBLOCK);
    if (-1 == result)
    {
      perror("fcntl() failed setting O_NONBLOCK");

      goto lblExit;
    }
  }

  /* Loop reading from the stream until it is emtpy: */
  do
  {
    char c = 0;
    ssize_t bytesRead = read(fd, &c, 1);
    if (-1 == bytesRead)
    {
      if ((EAGAIN != errno) && (EWOULDBLOCK != errno))
      {
        perror("read() failed");

        result = -1;
      }

      break;
    }
  } while (1);

  if (!(flags & O_NONBLOCK)) /* If stream had not be non-blocking */
  {                          /* re-set it to not be non-blocking. */
    int result_fcntl = fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
    if (-1 == result_fcntl)
    {
      perror("fcntl() failed setting flags");

      if (0 == result) /* Do not overwrite prvious error! */
      {
        result = result_fcntl;
      }

      goto lblExit;
    }
  }

lblExit:

  return result;
}

/* To test this: */
int main(void)
{
  int fd = fileno(stdin);

  printf("Feed some chars via the keyboard now!\n");

  sleep(3);

  printf("Game Over! Press enter to see stdin is empty\n");

  if (-1 == flush_inputstream(fd))
  {
    fprintf(stderr, "flush_inputstream() failed");
    return EXIT_FAILURE;
  }

  char s[16] = "";
  if (NULL == fgets(s, sizeof(s), stdin))
  {
    perror("fgets() failed");
  }

  printf("%s\n", s);

  return EXIT_SUCCESS;
}

答案 1 :(得分:0)

有两个不同的问题。第一个是我称之为流量控制的东西。在“发送者”(例如使用控制台应用程序的快速打字员)发送数据的速度比“接收器”(例如慢速控制台应用程序软件)可以接收数据的情况下,您不希望丢失数据并希望拥有缓冲区防止数据丢失。

举一个简单的例子,如果你的讲师尽可能聪明,他们可能会通过使用自动脚本预先测试学生的作业来让自己的生活变得更轻松。在这种情况下,STDIN实际上是一个文件(将检查来自STDOUT的数据以查看它是否与预期的模式匹配)。通过丢弃STDIN中的所有内容,您将丢弃所有输入并失败。

第二个问题是保持应用程序与其输入同步。这通常是通过获取一行用户输入(然后解析它并使用已解析的数据执行某些操作),然后获取下一行等来完成的。如果您这样做错了(例如,只获取输入行的一部分)那么您需要找到一种方法来处理你提取的内容和行尾之间的任何字符。这里的简单解决方案是开始时没有做错 - 例如使用“获取整行用户输入”功能(可能是gets())并担心在获得用户输入后解析用户输入行。

另请注意,理智的软件会通过生成某种“...之后的未知字符”错误消息来处理不需要/意​​外的字符,而不是通过丢弃/忽略它们。最好在解析期间执行此操作,而不是在解析当您使用(可能是错误的)用户输入的数据执行某些操作时。举一个简单的例子,假设“输入你的年龄:22个月” - 在这种情况下,你希望用户输入年份,你看到“22”然后看到“月”然后产生错误(“输入错误 - 请输入'年龄'作为单一年数“)。你不只是假设用户想要22年。

答案 2 :(得分:-1)

没有可移植的方法,因为默认情况下标准输入是“阻塞”,如果没有输入,则无法从中读取输出而不会导致阻塞。

如果有,可以使用select()检测是否有输入,然后执行读取以丢弃它。在这种情况下,我建议做一个“大”块读取,而不是一次只做一个字符。

请注意,getchar() returns int,常量EOF 不适合某个角色。这是"out of band" communication的一个例子,它不是一个角色。