我正在阅读《C程序设计语言》一书,目前为止我理解了所有内容。但是当我遇到getchar()
和putchar()
时,我无法理解它们的用途,更具体地说,下面的代码是做什么的。
main()
{
int c;
while ((c = getchar()) != EOF)
putchar(c);
}
我理解main()
函数,整数c
的声明和while
循环,但是我对while
循环中的条件感到困惑。这段C代码的输入是什么,输出又是什么?
我正在阅读《C程序设计语言》一书,目前为止我理解了所有内容。但是当我遇到getchar()
和putchar()
时,我无法理解它们的用途,更具体地说,下面的代码是做什么的。
main()
{
int c;
while ((c = getchar()) != EOF)
putchar(c);
}
我理解main()
函数,整数c
的声明和while
循环,但是我对while
循环中的条件感到困惑。这段C代码的输入是什么,输出又是什么?
这段代码可以更清晰地写成:
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
}
}
当没有更多输入时,会接收到EOF
字符。在从实际文件读取输入而不是用户输入(这是文件的特殊情况)的情况下,该名称更有意义。
main
函数编写为int main(void)
。]EOF
不是一个字符。 - Ayxan Haqverdiligetchar()
是一个从标准输入读取字符的函数。EOF
是在C语言中用来表示已经达到文件结尾的特殊字符。
通常情况下,当你的标准输入不是来自控制台(比如文件)时,getchar()
函数将返回一个 EOF
字符。
如果你在类 Unix 系统中以这种方式运行程序:
$ cat somefile | ./your_program
如果你使用getchar()
函数从somefile
中获取字符,当somefile
结束后,getchar()
将会返回每个字符以及EOF
。
如果你像下面这样运行你的程序:
$ ./your_program
通过控制台发送 EOF
(在 Unix 中按下 CTRL+D
或在 Windows 中按下 CTRL+Z),然后 getchar()
也会返回 EOF
,执行将结束。
getchar()
演示多态的好例子。从文件(输入)中读取,也可以从键盘(输入)中读取。 - overexchange./your_program < input_file
的方式。 - DevUt#include <stdio.h>
int main(void)
{
int c;
while ((c = getchar()) != EOF)
putchar(c);
}
int c;
while (1) {
c = getchar();
if (c != EOF)
putchar(c);
else
break;
}
这段代码的含义是:
c
中c
中的字符输出到 标准输出流 中许多编程语言通过 抛出异常 来处理异常情况以打破正常程序流程,但 C 并不如此。相反,可能失败的函数会有一个返回值,并且任何异常情况都通过特殊返回值来表示,您需要从给定函数的文档中检查该值。对于 getchar
函数,C11 标准的文档说明如下 (C11 7.21.7.6p3):
getchar
函数从由stdin
指向的输入流中返回下一个字符。如果流已到达文件结尾,则设置流的文件结尾指示器,并使getchar
返回EOF
;如果读取出错,则设置流的错误指示器,使getchar
返回EOF
。
另外还说明了 EOF
是一个小于 0 的整数常量,而任何普通返回值都大于等于 0 —— 这个值是零扩展为 int
的无符号字符。
当输入流到达文件结尾时就意味着所有输入都已被使用完毕。在标准输入流中,可以通过在 Unix/Linux 终端上按下 Ctrl+D,或者在 Windows 控制台窗口中按下 Ctrl+Z 来引发这种情况。另一个可能性是程序从文件或管道中接收输入而不是从键盘中接收输入——那么只要该输入被完全使用,就会发出文件结尾信号。
cat file | ./myprogram
或者
./myprogram < file
getchar
返回EOF
: 要么到达了文件结尾,要么发生了实际错误。这不能仅从返回值中推断出来。相反,您必须使用feof
和ferror
函数。feof(stdin)
在标准输入达到文件结尾时返回一个true值。ferror(stdin)
如果发生错误则返回true。<errno.h>
定义的变量errno
将包含错误代码;函数perror
可用于自动显示带有前缀的人类可读的错误消息。因此,我们可以扩展示例:#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('?');
}
}
^D
):% ./a.out
Hello world
Hello world
^D
end-of-file reached
注意这里的输入是行缓冲的,因此输入不会与输出在同一行中交错。
同样地,我们可以通过使用管道来实现相同的效果。
% echo Hello world | ./a.out
Hello world
end-of-file reached
<&-
:% ./a.out <&-
An error occurred. errno set to 9
Human readable explanation: Bad file descriptor
坏文件描述符或EBADF
表示标准输入 - 文件描述符号0无效,因为它根本没有被打开。
另一种有趣的生成错误的方法是从目录读取标准输入 - 这会导致Linux上的errno设置为EISDIR
:
% ./a.out < /
An error occurred. errno set to 21
Human readable explanation: Is a directory
putchar
的返回值也应该被检查——它在发生错误时同样会返回 EOF
,或者返回已写入的字符。while ((c = getchar()) != EOF) {
if (putchar(c) == EOF) {
perror("putchar failed");
exit(1);
}
}
现在我们可以通过将标准输出重定向到/dev/full
来测试 - 但是有一个陷阱 - 由于标准输出被缓冲,我们需要写入足够的内容以立即刷新缓冲区而不是在程序结束时。我们从/dev/zero
获得无限的零字节:
% ./a.out < /dev/zero > /dev/full
putchar failed: No space left on device
提示:在存储getchar()
的返回值时,始终使用int
类型的变量非常重要。即使它读取一个字符,使用有符号/无符号/普通的char
都是错误的。
getchar()函数从键盘(即stdin
)读取一个字符。
在给定的while
循环的条件中,在每次迭代之前调用getchar()
并将接收到的值赋给整型变量c
。
现在,必须理解,在C语言中,标准输入(stdin
)就像文件一样。也就是说,输入有缓冲区。输入将保留在缓冲区中,直到实际使用它。
stdin
实际上是标准输入流。
getchar()
返回输入缓冲区中的下一个可用值。
该程序基本上显示从键盘读取的任何内容,包括空格符\n
(换行)、空格等。
也就是说,输入是用户通过键盘提供的输入(stdin
通常表示键盘)。
而输出则是我们所提供的输入。
我们提供的输入逐个字符地读取并作为字符处理,即使我们将它们作为数字输入也是如此。
getchar()
仅在到达文件结尾时返回EOF
。我们在这里关心的“文件”实际上是stdin
本身(标准输入)。
想象一下一个存在的文件,其中通过键盘提供的输入正在被存储。那就是stdin
。
这个“文件”就像一个无限的文件。所以没有EOF
。
如果我们提供的输入比getchar()
一次可以处理的更多(在按回车之前),则额外的值仍将存储在未使用的输入缓冲区中。
getchar()
将从输入中读取第一个字符,将其存储在c
中,并用putchar(c)
打印 。
在while
循环的下一次迭代中,上一次迭代期间给出但仍在stdin
中的额外字符通过while ((c = getchar()) != EOF)
与c=getchar()
一起被获取。
现在,同样的过程重复进行,直到输入缓冲区中没有剩余内容为止。
这使得看起来putchar()
返回一个字符串而不是每次返回单个字符,如果在一个迭代中输入了多个字符。
abcdefghijkl
abcdefghijkl
putchar(c);
之后添加fflush(stdin);。
这将导致循环仅打印每次迭代期间提供的输入中的第一个字符。adgbad
a
将被打印出来。stdin
。getchar()
的相反操作。它将输出写入标准输出流(stdout
,通常是监视器)。
EOF
不是文件中存在的字符。它是由函数作为错误代码返回的东西。while
循环。输入缓冲区将在通过键盘输入任何内容并且stdin
不会给出EOF
时被清空(用于显示到输出)。EOF
,在Windows中可以通过键盘按ctrl+Z发送EOF
。while ((c = getchar()) != EOF)
{
putchar(c);
fflush(stdin);
}
printf("\nGot past!");
EOF
,则在退出程序之前将显示消息Got past!
。stdin
尚未为空,则需要按两次此键组合。一次清除此缓冲区,然后模拟EOF
。while ((c = getchar()) != EOF)
中,额外的括号围绕c = getchar()
是为了确保在将该值与EOF
进行比较之前,getchar()
返回的值首先被赋给c
。while (c = (getchar() != EOF) )
,这意味着c
可以有两个值之一:1
(为真)或0
(为假),这显然不是预期的结果。getchar()
将其读取为两个字符,即负号和数字1。在赋值给c时,该字符被转换为ASCII数值。该数值存储在某个内存位置中,由c访问。putchar(c)
检索此值,查找ASCII表并将其转换回字符,然后进行打印。getchar()
必须考虑不同平台上的不同解决方案。也许每个平台都有一个相应的getchar()
版本? getchar()
c = getchar()
EOF
的值为 -1
。 ((c = getchar()) != EOF)
EOF
,或者换句话说,只要条件保持为真,循环就会继续迭代。一旦值变成EOF
,整个条件的值将为0
并且它将打破循环。
c = getchar()
周围的额外括号是为了编译器,以强调我们确实想在条件内执行赋值操作,因为它通常会假定您想键入==
并发出警告。 main() {
int c;
while ((c = getchar()) != EOF)
putchar(c);
}
main(){
int c;
while ((c = getchar()) != EOF)
putchar(c);
}
实际上,c=getchar() 提供了用户在控制台输入的字符,并将该值与 EOF 进行比较,EOF 表示文件结尾。EOF 在文件末尾遇到。 (c = getchar()) != EOF 等同于 c != EOF。现在我认为这更容易理解了。如果您有任何进一步的问题,请告诉我。
类似于上面的 | 管道命令,您可以在系统上使用重定向来利用上述代码显示文件的所有字符内容,直到它达到通常由 CTRL-Z 或 CTRL-D 表示的结尾(EOF)。
在控制台中:
程序名称 < 文件名1.txt
要创建从 FileName1 读取的副本,您可以执行以下操作:
程序名称 < 文件名1.txt > 输入的副本.txt
这展示了您的程序的多种方式,希望有助于您的理解。
-希望这有所帮助。
int getchar(void)
每次调用时返回下一个输入字符,或者在遇到文件结束时返回EOF?虽然这是事实,并且与主题无关!