【问题标题】:When my program reads CTRL-D from standard input on Linux, why does it not convert to EOF?当我的程序在 Linux 上从标准输入读取 CTRL-D 时,为什么它不转换为 EOF?
【发布时间】:2012-04-03 04:09:13
【问题描述】:

下面是我写的程序。

/*******************************************************************************
 * This program reads EOF from standard input stream to store in an integer 
 * variable and in a character variable. Both values are then output to see the
 * stored value as integer.
*******************************************************************************/
#include<stdio.h>

int main (void)
{
    /* Local Declarations */
    int        num;
    char       ch;

    /* Read EOF as character & integer and display values stored */
    printf("\nPlease only input EOF for all input prompts below");
    printf("\nNumber? ");
    scanf("%d", &num);
    printf("\nThat integer input converts to %d", num);
    printf("\nCharacter? ");
    scanf(" %c", &ch);
    printf("\nThat character input converts to %d", ch);

    /* Check if any of the stored values are recognized as EOF */
    if(num == EOF)
        printf("\nNumber is an EOF");
    if(ch == EOF)
        printf("\nCharacter is an EOF");

    /* Exit Program */
    printf("\n");
    return 0;
}// main()

我在 Ubuntu 11.10 上使用 gcc 编译。它无法识别程序中 EOF 的 Ctrl-D 并在尝试打印其值时输出 0。上面程序在我的终端上的输出如下。

Please only input EOF for all input prompts below
Number? 
That integer input converts to 0
Character? 
That character input converts to 0

注意:当我为两个输入按下 CTRL-D 时,终端不会回显 CTRL-D,因此在上述程序执行中不可见。

我读过 EOF 在 stdio.h 和 stdlib.h 中被定义为一个整数,并且传统上定义为 -1。另外,我知道 Ctrl-D 模拟标准输入的 EOF。那为什么将其存储到整数变量时不转换为-1?

【问题讨论】:

  • 你的程序应该调用fflush,并在printf格式字符串的end中有\n
  • @BasileStarynkevitch 感谢您指出这一点。在开始读取字符值之前,我必须刷新流以读取 int 值。但是为什么建议将\n 放在printf 格式字符串的末尾而不是开头呢?我在我用来学习 C 的 book 中看到了这个约定,发现它有点奇怪。
  • 因为printf 的许多实现都在\n 换行符处刷新输出缓冲区。所以你的书在这方面是错误的,你真的应该养成把它放在格式字符串末尾的习惯。这就是大多数 Linux 实用程序(例如 shell、makegcc 本身)正在做的事情。
  • @BasileStarynkevitch 在 EOL 上刷新输出缓冲区?我认为当文件标记放在 EOF 上时,输出流会被刷新。请告诉我们更多信息(我知道您是 GCC 开发人员:-)。
  • 详细了解setlinebuf 函数。在 Linux 上(可能在 Posix 系统上),当 stdout 是终端时,它通常是行缓冲的。

标签: c linux eof


【解决方案1】:

因为scanf("%d") 会尝试读取代表数字的字符,然后将其存储到给定变量中。

如果您关闭流,它确实不会EOF 存储到号码中。否则,您将如何区分文件结尾和输入 EOF (-1) 的数值。

scanf 将返回扫描的项目数(如果格式错误,则返回零,如果流关闭或发生某些错误,则返回 EOF)。它会将此作为 scanf 函数的返回码返回,不是通过您传递给它的指针变量。

如果scanf 的返回值告诉你,你应该只假设变量(你传入的地址)被填充。

换句话说,您正在寻找类似的东西:

int rc = scanf ("%d", &num);
switch (rc) {
    case EOF: {
        printf ("EOF returned\n");
        break;
    }
    case 0: {
        printf ("No items scanned\n");
        break;
    }
    default: {
        printf ("Scanned %d\n", num);
        break;
    }
}

【讨论】:

  • 那么这意味着当在一个流中找到EOF时,它是关闭的,而不是传递给相应的流指针(或变量)?而且我们无法将 EOF 从流中读取到变量中?
  • 是的,你可以把它读入一个变量就好了——请看我把它放入rc的代码。你不能做的是让它神奇地出现在num 中——只有在输入流上有可用的数字时才会填充。从scanf 返回两条(或更多条)信息 - 返回码为您提供错误指示或扫描的项目数,您传入的变量指针为您提供扫描的实际值(如果有)。跨度>
  • 根据我们在此处的讨论,我发现了一个新问题。我必须编写一个只返回正整数的函数。如果用户不输入,则丢弃并提示用户重新输入。我用这段代码do{ scanf("%d", &amp;num) } while(num &lt; 0);实现了这个功能。但是,该问题还指定如果用户要输入 EOF,该函数也应该返回它。这是我碰壁的地方,因为无论我尝试什么,我都无法按照您的建议从输入流中获取 EOF 并将其存储在传递的变量指针中。你有什么建议?
【解决方案2】:

来自the docs

"如果输入在第一次匹配失败或转换之前结束,则返回EOF。如果发生读取错误,则设置流的错误指示符,返回EOF"

注意它是返回的,而不是被读入你传递的指针。

要区分错误和 EOF,您可以使用 feof

【讨论】:

    猜你喜欢
    • 2020-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-02
    相关资源
    最近更新 更多