fgets在换行前设置null char后清除输入流

时间:2017-08-02 19:56:22

标签: c fgets

我有一个用户输入两个输入的程序。由于我无法控制用户输入的内容,因此用户可以超过阵列的固定大小。由于 String arr_name = "array 1"; ....replace(String.format ("{\"%s\"", arr_name), ""); 追加在空字符之前保留了一个换行符,如果在用户超出预期大小时换行符不适合,则空字符会截断输入。用户命中输入时的换行符是否仍存在于输入流中?如果是这样,这是fgets()由于第一次输入换行而第二次跳过的原因吗?

fgets()

示例输入    #include <stdio.h> int main(){ char str[5]; fgets(str,5,stdin); printf("Output:%s",str); fgets(str,5,stdin); printf("Output:%s",str); return 0; }

输出

ABCDE\n

在阅读了这个SO回答fgets() isn't prompting user a second time 之后,问题似乎并没有通过Output:ABCDOutput:E 刷新输入流,但是我听到了相互矛盾的信息,因为这会导致未定义的行为。我的最后一个问题是,如果保留换行符导致问题,清除输入流的适当方法是什么?

4 个答案:

答案 0 :(得分:4)

  

用户可以超过数组的固定大小。由于fgets()在空字符

之前的末尾附加换行符

不,它没有。它将从输入读取的字符写入提供的缓冲区,直到并包括第一个换行符,或直到指定的缓冲区大小耗尽(字符串终结符少于一个字节),或者直到发生错误或者到达流的末尾,以先到者为准。换行符不是由fgets()发明的;它来自输入。

  

,如果在用户超出预期大小时换行符不适合,则空字符会截断输入。用户命中输入时的换行符是否仍存在于输入流中?

用户输入但未复制到缓冲区中的所有字符仍等待在流中读取。如果用户输入了换行符,那将包括换行符。

  

如果是这样,这是因为第一次输入的换行符导致fgets()第二次跳过的原因吗?

fgets()没有跳过,但它确实在前一个调用停止从输入到缓冲区传输字符的位置。没有字符丢失。这意味着如果第一个调用没有返回整个内容,第二个调用将返回第一个输入行的一部分。您需要以某种方式考虑输入不符合您的行长预期的可能性。

  

问题似乎不是通过fflush(stdin)

刷新输入流

不,不是。刷新用于将缓冲的输出发送到底层输出设备。刷新输入流会产生未定义的行为。原则上,这可能表现为缓冲区转储,并且给定的实现甚至可能指定此类行为, 但您不希望 因为可能有比缓冲更多的数据你想摆脱它。

  

但我听到有相互矛盾的信息说这会导致未定义的行为。我的最后一个问题是,如果保留换行符导致问题,清除输入流的适当方法是什么?

您从输入中读取,直到您阅读换行符。有很多I / O函数可供选择来完成此任务。 fgets()本身可能很方便,因为你已经在使用它了:

char str[5];

if (fgets(str, 5, stdin)) {
    printf("Output:%s", str);
    // read and consume the tail of the line, if any (overwrites str)
    while (!strchr(str, '\n') && fgets(str, 5, stdin)) { /* empty */ }
}

答案 1 :(得分:4)

fgets()读到

1)新线
2)缓冲区满了 3)文件结束
4)输入错误(罕见)

此代码读取并处理#3&amp; #4

 #define N 5
 char buf[N];
 if (fgets(buf, sizeof buf, stdin) == NULL) {
   // Handle EOF or Error
   return EOF;
 }

区分是否存在'\n' ......(来自#1的#2)

 // look for a lack of \n
 if (strchr(buf, '\n') == NULL) {

如果是,请阅读直到找到它或EOF

   int ch;
   while ((ch = fgetc(stdin)) != '\n' && ch != EOF);
 }

-

请勿使用以下代码。可以通过读取 null字符作为第一个字符来利用它。

 size_t len = strlen(buf);
 if (buf[len - 1] != '\n') {  // bad way to detect \n

可以使用

 if (len > 0 && buf[len - 1] != '\n') {  // Good

答案 2 :(得分:4)

  

因为我无法控制用户输入的内容......

不,你不能。

  

用户可以超过数组的固定大小。

右。这一直是一个问题。但是,一般来说,你会想要安排一些事情,这样很少发生。

例如,如果你真的想要将用户限制为(比方说)4个字符长的输入字符串,让他输入他想要的任何内容,然后查看他输入的内容,以及是否超过了你的限制,打印一个很好的错误消息或东西。但是,如果您预计输入4个字符加上换行符,我建议不要拨打fgets(str, 5, stdin),因为当用户输入的内容过多时(而不是如果)输入太多,这就太难以恢复了。 / p>

  

如果在用户超出预期大小时换行符不适合,则空字符会截断输入。用户命中输入时的换行符是否仍存在于输入流中?

绝对是的。

  

如果是这样,这是因为第一次输入的换行符导致fgets()第二次跳过的原因吗?

非常好。

我建议分配一个更大的缓冲区,然后继续这样的事情:

char inpbuf[512);
if(fgets(inpbuf, sizeof(inpbuf), stdin) == NULL) {
    fprintf(stderr, "end of file\n");
    return;
}
char *p = strrchr(inpbuf, '\n');
if(p == NULL) {
    fprintf(stderr, "looks like you typed *way* too much\n");
    return;
}
*p = '\0';        /* erase the \n */
if(strlen(inpbuf) > 4) {
    fprintf(stderr, "you typed too much (max 4)\n");
    return;
}
strcpy(str, inpbuf);
printf("Output:%s", str);

编写此代码的一个小问题是:如果用户在点击Return之前点击文件结束键(Unix / Linux上的control-D),你就会错误地得到&#34;看起来就像你输入方式太多&#34;消息。

答案 3 :(得分:3)

如果fgets读取的字符串不以换行符结尾,则表示它仍在缓冲区中。在这种情况下,请在循环中调用getchar,直到获得换行符。

fgets(str,5,stdin);
printf("Output:%s",str);
if (strchr(str, '\n') == NULL) {
    int c; 
    while ((c = getchar()) != EOF && c != '\n');
}

fgets(str,5,stdin);
printf("Output:%s",str);