实际结束从终端读取需要两个 EOF
Two EOF required to actually end reading from terminal
我一直在努力了解 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;
}
我的输出:
我有这样的疑问:-
为什么需要两个 EOF
?以及如何防止第一个被读取(作为一些垃圾)并存储为我输入的一部分?
尝试将 c
的类型更改为 int
,因为 EOF
可以是负数,通常定义为 -1
。 char
可能无法存储 -1
。另外,不要忘记在将字符串传递给 puts
之前以 [=16=]
结尾。
Control-Z 仅在新行的开头被识别为 EOF
。因此,如果你想在一条线的中间检测它,你需要自己做。
因此更改此行:
while((c = getchar()) != EOF)
对此:
while((c = getchar()) != EOF && c != CTRL_Z)
然后添加:
#define CTRL_Z ('Z' & 0x1f)
在程序的顶部。
您可能还需要在 Ctrl-z[=29 之后输入 return =] 来让程序读取缓冲输入,但它应该丢弃 ^Z.
之后的所有内容
以下解决方案修复了 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()
到 return EOF (-1) 的文件结尾,否则它会将 ASCII SUB (26) 字符插入流中. SUB 的使用最初是为了与更早的 CP/M 操作系统兼容 MS-DOS。特别是 CP/M 文件由固定长度的记录组成,因此记录中间的 ^Z 用于指示不是记录长度的精确倍数的文件的有效数据结束。在控制台中,如果 SUB 不在输入缓冲区的开头并且 SUB 之后的所有字符都被丢弃,则 SUB 是可读的而不是生成 EOF。都是回来后的一团乱麻。
Windows 终端在键盘输入中(至少在默认配置中)遵循的关于 ^Z
的逻辑如下:
Ctrl-Z 组合本身不会导致输入行缓冲区被推送到等待的应用程序。此组合键只是在输入缓冲区中生成 ^Z
个字符。您必须按 Enter 完成该行缓冲区并将其发送到应用程序。
您实际上可以在 ^Z
之后和按 Enter 之前继续输入其他字符。
如果输入行不是以 ^Z
开头,而是在内部包含 ^Z
,则应用程序将收到该行直到 并包括 第一个 ^Z
字符(读作 \x1A
字符)。其余的输入被丢弃。
例如如果你输入
Hello^Z World^Z123
然后按 输入 你的 C 程序实际上会读取 Hello\x1A
序列。 EOF条件不会出现。
如果输入行以^Z
开头,则整行被丢弃并设置EOF条件。
例如如果你输入
^ZHello World
然后按 Enter 您的程序将不读取任何内容并立即检测 EOF。
这是您在实验中观察到的行为。请记住,getchar()
的结果应该接收到 int
变量,而不是 char
变量。
我一直在努力了解 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;
}
我的输出:
我有这样的疑问:-
为什么需要两个 EOF
?以及如何防止第一个被读取(作为一些垃圾)并存储为我输入的一部分?
尝试将 c
的类型更改为 int
,因为 EOF
可以是负数,通常定义为 -1
。 char
可能无法存储 -1
。另外,不要忘记在将字符串传递给 puts
之前以 [=16=]
结尾。
Control-Z 仅在新行的开头被识别为 EOF
。因此,如果你想在一条线的中间检测它,你需要自己做。
因此更改此行:
while((c = getchar()) != EOF)
对此:
while((c = getchar()) != EOF && c != CTRL_Z)
然后添加:
#define CTRL_Z ('Z' & 0x1f)
在程序的顶部。
您可能还需要在 Ctrl-z[=29 之后输入 return =] 来让程序读取缓冲输入,但它应该丢弃 ^Z.
之后的所有内容以下解决方案修复了 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()
到 return EOF (-1) 的文件结尾,否则它会将 ASCII SUB (26) 字符插入流中. SUB 的使用最初是为了与更早的 CP/M 操作系统兼容 MS-DOS。特别是 CP/M 文件由固定长度的记录组成,因此记录中间的 ^Z 用于指示不是记录长度的精确倍数的文件的有效数据结束。在控制台中,如果 SUB 不在输入缓冲区的开头并且 SUB 之后的所有字符都被丢弃,则 SUB 是可读的而不是生成 EOF。都是回来后的一团乱麻。
Windows 终端在键盘输入中(至少在默认配置中)遵循的关于 ^Z
的逻辑如下:
Ctrl-Z 组合本身不会导致输入行缓冲区被推送到等待的应用程序。此组合键只是在输入缓冲区中生成
^Z
个字符。您必须按 Enter 完成该行缓冲区并将其发送到应用程序。您实际上可以在
^Z
之后和按 Enter 之前继续输入其他字符。如果输入行不是以
^Z
开头,而是在内部包含^Z
,则应用程序将收到该行直到 并包括 第一个^Z
字符(读作\x1A
字符)。其余的输入被丢弃。例如如果你输入
Hello^Z World^Z123
然后按 输入 你的 C 程序实际上会读取
Hello\x1A
序列。 EOF条件不会出现。如果输入行以
^Z
开头,则整行被丢弃并设置EOF条件。例如如果你输入
^ZHello World
然后按 Enter 您的程序将不读取任何内容并立即检测 EOF。
这是您在实验中观察到的行为。请记住,getchar()
的结果应该接收到 int
变量,而不是 char
变量。