实际结束从终端读取需要两个EOF

时间:2018-08-12 09:18:37

标签: c windows input eof

我一直在尝试了解EOF的工作方式。在我的代码中(在Windows上),调用EOF Ctrl + Z Enter )第一次无效,我必须提供两个EOF才能真正停止读取输入。另外,第一个EOF被读取为一些垃圾字符,当我打印输入时会显示这些垃圾字符。 (我们可以在提供的输出中看到垃圾字符显示在末尾。)

这是我的代码:-

#include<stdio.h>

#define Max 1000

int main()
{
    char c, text[Max];
    int i = 0;

    while((c = getchar()) != EOF)
    {
        text[i] = c;
        i++;
    }

    printf("\nEntered Text: \n");
    puts(text);

    return 0;
}

我的输出:

My Output:

我对此有疑问:-

为什么需要两个EOF?以及如何防止第一个被读取(作为一些垃圾)并存储为输入的一部分?

4 个答案:

答案 0 :(得分:2)

Control-Z仅在换行开始时才被识别为EOF。因此,如果您想在一行的中间进行检测,则需要自己进行检测。

因此更改此行:

while((c = getchar()) != EOF)

对此:

while((c = getchar()) != EOF && c != CTRL_Z)

然后添加:

#define CTRL_Z ('Z' & 0x1f)

位于程序顶部。

您可能仍需要在 Ctrl - z 之后键入 return ,以获取要由程序读取的缓冲输入,但是应该丢弃^ Z之后的所有内容。

答案 1 :(得分:1)

尝试将c的类型更改为int,因为EOF可以为负数,通常将其定义为-1char可能或可能无法存储-1。另外,在将字符串传递给\0之前,请不要忘记以puts结尾的字符串。

答案 2 :(得分:1)

以下解决方案解决了Ctrl + Z问题和垃圾输出,还阻止了缓冲区溢出。我评论了这些变化:

#include <stdio.h>

#define Max 1000
#define CTRL_Z 26           // Ctrl+Z is ASCII/ANSI 26

int main()
{
    int c ;                  // getchar() returns int
    char text[Max + 1] ;     // +1 to acommodate terminating nul
    int i = 0;

    while( i < Max &&                 // Bounds check
           (c = getchar()) != EOF && 
           c != CTRL_Z )              // Check for ^Z when not start of input buffer
    {
        text[i] = c;
        i++;
    }

    text[i] = 0 ;        // Terminate string after last added character

    printf( "\nEntered Text:\n" );
    puts( text );

    return 0;
}

此行为的原因有些不可思议,但是文件结尾与Ctrl-Z不同。当且仅当控制台输入缓冲区为空时,控制台才会生成文件结尾,导致getchar()返回EOF(-1),否则控制台将ASCII SUB(26)字符插入流中。 SUB的使用最初是为了与MS-DOS与甚至更早的CP / M操作系统兼容。特别是CP / M文件由固定长度的记录组成,因此记录中间的^ Z用于指示不是记录长度精确倍数的文件有效数据的结尾。在控制台中,如果SUB不在输入缓冲区的开头,并且SUB之后的所有字符都被丢弃,则它是可读的,而不是生成EOF。都是从回程的混乱宿醉。

答案 3 :(得分:0)

Windows终端在键盘输入(至少在其默认配置下)中针对^Z遵循的逻辑如下:

  • Ctrl-Z 组合本身不会导致输入行缓冲区被推送到等待的应用程序。此组合键仅在输入缓冲区中生成^Z字符。您必须按 Enter 完成该行缓冲区并将其发送到应用程序。

    实际上,您可以在^Z之后并按 Enter 之前继续输入其他字符。

  • 如果输入行不是以^Z开头,而是在其中包含^Z,则应用程序将接收直到并包括前{ {1}}个字符(读为^Z个字符)。其余的输入将被丢弃。

    例如如果您输入

    \x1A

    并按 Enter 您的C程序将实际读取Hello^Z World^Z123 序列。不会出现EOF条件。

  • 如果输入行以Hello\x1A开头,则会丢弃整行并设置EOF条件。

    例如如果输入

    ^Z

    ,然后按 Enter ,您的程序将不会读取任何内容,并立即检测到EOF。

这是您在实验中观察到的行为。请记住,应该将^ZHello World 的结果接收到getchar()变量中,而不是int变量中。