Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
清除C中的标准输入,无论其是否为空_C_Stdin - Fatal编程技术网

清除C中的标准输入,无论其是否为空

清除C中的标准输入,无论其是否为空,c,stdin,C,Stdin,我是一名编程专业的学生,正在寻找摆脱stdin中可能出现的字符的方法。我尝试了一种在这里以各种形式给出的技术,你可以这样做: void clearStdIn(void) { char c; while((c = getchar()) != '\n' && c != EOF) /* discard */ ; } #include <stdlib.h> #include <stdio.h> #include <unis

我是一名编程专业的学生,正在寻找摆脱stdin中可能出现的字符的方法。我尝试了一种在这里以各种形式给出的技术,你可以这样做:

void clearStdIn(void) 
{
    char c;
    while((c = getchar()) != '\n' && c != EOF)
        /* discard */ ;
}
#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;
}

问题似乎是,如果stdin中没有任何内容,那么这个函数将一直等待用户在控制流继续之前点击enter。我该怎么办

没有可移植的方法可以做到这一点,因为默认情况下,标准输入是“阻塞”的,如果没有输入,您无法从中读取,以便在不造成阻塞的情况下丢弃输入

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


请注意,常量
EOF
不适合字符。这是一个例子,它不是一个角色

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

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

第二个问题是保持应用程序与其输入同步。这通常是通过获取一行用户输入(然后对其进行解析并对解析后的数据执行某些操作),然后获取下一行,等等来完成的。如果您这样做错误(例如,仅获取输入行的一部分),则需要找到一种方法来处理所获取内容的结尾和该行结尾之间的任何字符。这里的简单解决方案是不要从一开始就做错事-例如,使用“获取整行用户输入”函数(可能是
gets()
),并担心在获取用户输入行后解析该行

还要注意的是,sane软件将通过生成某种类型的“未知字符之后…”错误消息来处理不需要的/意外的字符,而不是通过丢弃/忽略它们。最好在解析过程中执行此操作,而不是在解析之后使用来自(可能错误的)用户输入的数据执行操作。举一个简单的例子,假设“输入您的年龄:22个月”-在这种情况下,您希望用户输入年,您看到“22”然后看到“月”,然后生成一个错误(“输入错误-请输入“年龄”作为一个年数”)。你不能仅仅假设用户想要22年。

在不阻塞的情况下刷新输入流(以便携方式)可以这样做:

void clearStdIn(void) 
{
    char c;
    while((c = getchar()) != '\n' && c != EOF)
        /* discard */ ;
}
#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;
}
#包括
#包括
#包括
#包括
#包括
int flush\u输入流(int fd)
{
int结果=0;
int flags=fcntl(fd,F_GETFL);
如果(-1==标志)
{
perror(“fcntl()获取标志失败”);
结果=-1;
后进先出;
}
如果(!(标志&O_非阻塞))/*如果流不是非阻塞的*/
{/*将其设置为非阻塞*/
结果=fcntl(fd、F_设置FL、O_非块);
如果(-1==结果)
{
perror(“fcntl()设置O_非块失败”);
后进先出;
}
}
/*循环从流中读取,直到它是emtpy:*/
做
{
字符c=0;
ssize_t bytesRead=read(fd,&c,1);
如果(-1==字节读取)
{
if((EAGAIN!=errno)&(ewoolblock!=errno))
{
perror(“读取()失败”);
结果=-1;
}
打破
}
}而(1),;
if(!(flags&O_NONBLOCK))/*如果流不是非阻塞的*/
{/*将其重新设置为非阻塞*/
int result_fcntl=fcntl(fd、F_SETFL、标志和非块);
如果(-1==结果\u fcntl)
{
perror(“fcntl()设置标志失败”);
如果(0==结果)/*请不要覆盖上一个错误*/
{
结果=结果\u fcntl;
}
后进先出;
}
}
lblExit:
返回结果;
}
/*要测试这一点:*/
内部主(空)
{
int fd=文件号(标准输入);
printf(“现在通过键盘输入一些字符!\n”);
睡眠(3);
printf(“游戏结束!按enter键查看标准输入为空\n”);
如果(-1==flush_inputstream(fd))
{
fprintf(stderr,“flush_inputstream()失败”);
返回退出失败;
}
字符s[16]=“”;
如果(NULL==fgets,sizeof,stdin))
{
perror(“fgets()失败”);
}
printf(“%s\n”,s);
返回退出成功;
}

您想做什么?stdin通常没有字符,因此你可能会处于一种非常罕见的情况下…@mander:通常对于控制台应用程序,键入输入的人可以领先于程序。这很少见(软件速度很快),但只会让有经验的用户更容易使用。取消/放弃输入意味着快速用户必须停止并等待软件赶上,这将给用户带来问题,这是一个坏主意。标准方法标准没有确定字符是否留在输入缓冲区中的功能。因此,它将依赖于处理实现(例如fflush(stdin)、revend(stdin)等),或者更可能的情况是,在stdin中,从scanf之类的函数中,会留下作为垃圾的尾随换行符。所以这个函数可能很好:只需确保在调用scanf之后调用它。嗨,我正在使用fscanf加上一个字符串来缓冲用户输入。如果用户输入的字符数超过缓冲区可以处理的字符数,则该函数将按广告方式工作,但如果输入的字符数低于限制,则该函数将挂起。问题是,我们(C编程学生)不应该使用gets(),因为缓冲区可能会溢出。所以,我用了fscan