main()
{
int c;
while (1) {
c = getchar(); // Get one character from the input
if (c == EOF) { break; } // Exit the loop if we receive EOF ("end of file")
putchar(c); // Put the character to the output
}
}
#include <stdio.h>
#include <errno.h> // for the definition of errno
#include <stdlib.h> // for exit()
int main(void)
{
int c;
while ((c = getchar()) != EOF)
putchar(c);
if (feof(stdin)) {
printf("end-of-file reached\n");
exit(0);
}
else if (ferror(stdin)) {
printf("An error occurred. errno set to %d\n", errno);
perror("Human readable explanation");
exit(1);
}
else {
printf("This should never happen...\n");
exit('?');
}
}
要触发文件结束,可以在Linux上的新行中使用Ctrl+D(这里显示为^D):
% ./a.out
Hello world
Hello world
^D
end-of-file reached
9条答案
按热度按时间bqucvtff1#
这段代码可以更清楚地写为:
EOF
字符在没有更多输入时被接收。在从真实的文件读取输入而不是用户输入(这是文件的特殊情况)的情况下,该名称更有意义。[As顺便说一句,通常
main
函数应该写为int main(void)
。cig3rfwq2#
getchar()
是从标准输入读取字符的函数。EOF
是一个特殊字符,在C中用于声明已到达END OF FILE。通常,当您的标准输入不是控制台(即文件)时,您将从
getchar()
返回EOF
字符。如果你在unix中运行你的程序,像这样:
然后,
getchar()
将在somefile
结束时返回somefile
和EOF
中的每个字符。如果你像这样运行你的程序:
然后通过控制台发送一个
EOF
(在Unix中通过点击CTRL+D
或在Windows中通过CTRL+Z),然后getchar()
也将返回EOF
,执行将结束。t8e9dugd3#
使用当前C标准编写的代码应该是
该循环可以重写为
这读起来像
c
中c
中存储的字符输出到 * 标准输出 *许多编程语言通过引发异常来处理异常情况,这些异常会破坏正常的程序流程。C没有这样的事情。相反,可能失败的函数有一个返回值,任何异常条件都由一个特殊的返回值表示,您需要从给定函数的文档中检查。在
getchar
的情况下,C11标准中的文档说明(C11 7.21.7.6p3):getchar
函数返回stdin
指向的输入流中的下一个字符。如果流位于文件结尾,则设置流的文件结尾指示符,getchar
返回EOF
。如果发生读取错误,则设置流的错误指示符,并且getchar
返回EOF
。在其他地方说明
EOF
是一个< 0的整数常量,任何普通的返回值都是>= 0 -unsigned char
零扩展为int
。流位于文件末尾意味着所有输入都已被使用。对于标准输入,可以通过在Unix/Linux终端上键入Ctrl+D和在Windows控制台窗口中键入Ctrl+Z来从键盘上实现此操作。另一种可能性是程序从文件或管道接收输入,而不是从键盘接收输入,然后每当该输入被完全消耗时,文件结束将被发信号通知,即
或
正如上面的片段所说,实际上有两种不同的条件可以导致
getchar
返回EOF
:到达 * 文件结束 , 或 * 发生实际错误。这不能仅从返回值推导出来。相反,您必须使用函数feof
和ferror
。feof(stdin)
将返回一个true值,如果在标准输入上达到文件结束。ferror(stdin)
如果发生错误,将返回true。如果实际发生错误,
<errno.h>
定义的变量errno
将包含错误代码;函数X1 M20 N1 X可用于自动显示具有前缀的人类可读错误消息。因此,我们可以将示例扩展到要触发文件结束,可以在Linux上的新行中使用Ctrl+D(这里显示为
^D
):(注意这里的 input 是如何行缓冲的,所以输入不会在带有输出的行中交错)。
同样,我们也可以通过使用管道获得同样的效果。
触发一个错误就有点棘手了。在
bash
和zsh
shell中,标准输入可以 * 关闭 *,这样它就不会来自任何地方,通过将<&-
追加到命令行:EBADF
表示 * 标准输入 * -文件描述符号0无效,因为它根本没有被打开。另一种生成错误的有趣方法是从 * 目录 * 读取标准输入-这会导致在Linux上errno被设置为
EISDIR
:实际上,
putchar
的返回值也应该被检查-它同样返回EOF
错误,或者写的字符:现在我们可以通过将标准输出重定向到
/dev/full
来测试这一点--但是有一个陷阱--因为标准输出是缓冲的,我们需要写足够的 *,以使缓冲区立即刷新,而不是在程序结束时刷新。我们从/dev/zero
得到无限零字节:P.S.始终使用类型为 *
int
* 的变量来存储getchar()
的返回值是非常重要的。即使它读取 * 字符 *,usingsigned
/unsigned
/plainchar
is always wrong。u0njafvf4#
getchar()函数从键盘读取字符(即
stdin
)在给定的
while
循环中,getchar()
在每次迭代之前被调用,并且接收到的值被分配给整数c
。现在,必须理解,在C中,标准输入(
stdin
)是like文件。即输入被缓冲。输入将保留在缓冲区中,直到实际使用。stdin
实际上是standard input stream。getchar()
返回输入缓冲区中的下一个可用值。该程序基本上显示从键盘上读取的任何内容;包括白色,如
\n
(换行符)、空格等。即输入是用户通过键盘提供的输入(
stdin
通常指键盘)。而输出就是我们提供的任何输入。我们提供的输入是一个字符接一个字符地读取的&即使我们以数字的形式给予它们,也会被当作字符来处理。
getchar()
将返回EOF
只有当到达文件的结尾。我们在这里关注的“文件”是stdin
本身(标准输入)。想象一个文件存在于我们通过键盘提供的输入被存储的地方。就是
stdin
这个“文件”就像一个infinite file。所以没有EOF
。如果我们提供的输入比
getchar()
一次可以处理的要多(在按下回车键将其作为输入之前),额外的值仍然会存储在输入缓冲区中。getchar()
将从输入中读取第一个字符,将其存储在c and print
cwith
putchar(c)中。 在
while循环的下一次迭代中,上一次迭代中给出的仍在
stdin中的额外字符将在
while ((c = getchar()) != EOF)期间使用
c=getchar()部分。现在,重复相同的过程,直到输入缓冲区中没有任何剩余。 这使得
putchar()看起来像是在一次迭代中如果输入了多个字符,则一次返回一个字符串而不是单个字符。 例如:如果输入为
abcdefghijkl输出也是一样的
abcdefghijkl如果你不想要这种行为,你可以在
putchar(c);之后添加[fflush(stdin);](https://stackoverflow.com/questions/18170410/what-is-the-use-of-fflushstdin-in-c-programming)。这将导致循环在每次迭代期间仅打印输入中的第一个字符。 例如:如果输入为
adgbad将只打印
a。 只有在按下回车键后,输入才会发送到
stdin。 [putchar()](https://en.wikibooks.org/wiki/C_Programming/stdio.h/getchar)与
getchar()相反。它将输出写入标准输出流(
stdout,通常是监视器)。
EOF不是文件中的字符。它是函数返回的错误代码。 但是,您可能无法正常退出给予
while循环。输入缓冲区将清空(显示到输出),只要有东西进入它通过键盘和
stdin不会给予
EOF。 对于手动退出循环,可以使用键盘通过在Linux中按ctrl+D发送
EOF`,并且Windows中的Ctrl+Z
例如:
如果您按组合键给予
EOF
,退出程序前将显示消息Got past!
。如果
stdin
是not
已经为空,则必须按两次此组合键。一次清除此缓冲区,然后模拟EOF
。编辑:
while ((c = getchar()) != EOF)
中c = getchar()
周围的额外一对括号是为了确保在that
值与EOF
进行比较之前,先将getchar()
返回的值分配给c
。如果没有这个额外的括号,表达式实际上是
while (c = (getchar() != EOF) )
,这意味着c
可以有两个值之一:1
(表示真)或0
(表示假),这显然不是预期的结果。qlzsbp2j5#
也许你对在命令行中输入-1并不能结束程序这一事实感到困惑。因为
getchar()
将其读取为两个字符-和1。在对c的赋值中,字符被转换为ASCII数值。这个数值存储在某个内存位置,由c访问。然后
putchar(c)
检索这个值,查找ASCII表并转换回字符,然后打印出来。我想在ASCII表中找到十进制的-1值是不可能的,因为表从0开始。因此
getchar()
必须考虑不同平台上的不同解决方案。也许每个平台都有一个getchar()
版本?我只是觉得奇怪的是,这个EOF不是在常规的ascii。它可能是第一个字符之一,这是不可打印的。例如,End-of-line是ASCII。
如果你把你的文件从windows转移到linux会发生什么?EOF文件字符会自动更新吗?
ztyzrc3y6#
从输入中获取字符。
这个赋值的值是赋值后左边的值,或者是读取的字符的值。
EOF
的值默认为-1
。只要该值不是
EOF
,或者换句话说,只要条件为真,循环就会继续迭代。一旦值变成EOF
,整个条件的值将是0
,它将打破循环。c = getchar()
周围的括号是为编译器准备的,以强调我们确实希望在条件内进行赋值,因为它通常假设您希望键入==
并警告您。所以整个代码实际上会回显您输入的内容。它将字符的值赋给条件中的
c
,然后将其输出回循环体,仅在检测到文件结束时结束。xfyts7mz7#
以类似于|pipe命令,你可以在你的系统上使用重定向,利用上面的代码来显示文件的所有字符内容,直到它到达通常由CTRL-Z或CTRL-D表示的结尾(EOF)。
在控制台:
ProgramName < FileName1.txt
要创建从FileName 1读取的内容的副本,您可以:
ProgramName < FileName1.txt > CopyOfInput.txt
这以多种方式演示了您的程序,希望有助于您的理解。
j7dteeu88#
实际上,c=getchar()提供了用户在控制台上输入的字符,该值用EOF检查,EOF表示文件结束。文件的最后一个遇到EOF。(c = getchar())!= EOF等价于c!现在我觉得这就容易多了。如果你有任何进一步的疑问让我知道。
ovfsdjhp9#
为什么还没有人说
int getchar(void)
在每次调用时返回下一个输入字符,或者在遇到文件结尾时返回EOF?这是事实,但它不是出了问题!