我一直在尝试了解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
?以及如何防止第一个被读取(作为一些垃圾)并存储为输入的一部分?
答案 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
可以为负数,通常将其定义为-1
。 char
可能或可能无法存储-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
变量中。