我知道这已经在前面讨论过了,但是我想确保我正确理解了该程序中发生的事情以及原因。在丹尼斯·里奇(Dennis Ritchie)的教科书 C编程语言的第20页上,我们看到了以下程序:
#include <stdio.h>
int main()
{
int c;
c = getchar();
while(c != EOF){
putchar(c);
c = getchar();
}
return 0;
}
执行后,程序将读取键入的每个字符,并在用户按下Enter键后以相同顺序将其打印出来。除非用户手动退出控制台,否则将无限期重复此过程。事件的顺序如下:
getchar()
函数读取键入的第一个字符,并将其值分配给c
。
由于c
是整数类型,因此getchar()
传递给c的字符值被提升为其对应的ASCII整数值。
现在c
已被初始化为某个整数值,while循环可以测试该值是否等于文件尾字符。因为EOF
字符的宏值为-1
,并且因为所有可能键入的字符都不具有负十进制ASCII值,所以while循环的条件始终为true。
一旦程序验证c != EOF
为真,就会调用putchar()
函数,该函数将输出c
中包含的字符值。
getchar()
被再次调用,因此它读取下一个输入字符,并将其值传递回while循环的开始。如果用户在执行之前仅键入一个字符,则程序将读取<return>
值作为下一个字符并打印新行,并等待键入下一个输入。
其中任何一个远程正确吗?
答案 0 :(得分:1)
是的,您基本上已经掌握了。但这甚至更简单:getchar
和putchar
已经分别返回并接受int
类型。因此,没有类型升级发生。您只需要输入字符并循环发送它们,直到看到EOF
。
您关于为什么应该使用int
而不是某些char
形式的直觉很可能是正确的:int
类型允许哨兵EOF
值超出该值任何可能的字符值的范围。
(K&R stdio
函数目前非常很旧,它们不了解Unicode等,并且某些基本的设计原理即使不是很模糊,也不会相关。如今,没有太多实用的代码可以使用这些功能。这本书在很多方面都很出色,但是代码示例却是过时的。)
(此外,您的问题标题是“复制文件”,您仍然可以 这样操作,但还有更多规范的方法)
答案 1 :(得分:0)
好吧,这在思想上是正确的,但在细节上却不正确,那就是魔鬼所在的地方。
getchar()
函数从标准输入中读取第一个字符,并将其作为提升为unsigned char
的{{1}}返回(如果没有字符则返回特殊的int
值)已被读取)
返回值分配给EOF
,其类型为c
(应为if it were a char
strange things could happen)
现在已经为int
分配了一些整数值,c
循环可以测试该值是否等于while
宏的值。
由于EOF
宏具有实现指定的负值,并且由于字符被转换为EOF
并被提升为unsigned char
,它们都没有负值(至少在新手遇到的任何系统中都没有),int
循环的条件将一直为真,直到文件结束条件发生或读取标准输入时发生错误。
一旦程序验证while
为真,就会调用c != EOF
函数,该函数将输出putchar()
中包含的字符值。
c
被再次调用,因此它将读取下一个输入字符,并将其值传递回while循环的开始。
标准输入(如果连接到终端设备)通常是行缓冲的,这意味着该程序在用户完成该行并按<之前不会接收该行上的任何字符。 kbd>输入键。
我们使用的是执行字符集,而不是ASCII,如今,它们可能通常是UTF-8编码的Unicode字符的单个字节。 getchar()
在二进制中也是负数,我们不需要考虑“其十进制值”。 EOF
和char
类型也都是数字,字符常量的类型也是unsigned char
-例如,在执行字符集与ASCII 兼容的系统上,写int
与写32是一样的事情,尽管对于那些不记得ASCII码的人来说显然更清楚。
最后,C对初始化的含义非常严格。是在声明初始值时将其设置为变量。
' '
具有初始化。
int c = getchar();
已int c;
c = getchar();
未初始化,然后分配了一个值。知道这些区别后,当编译器错误消息引用 initialization 或 assignment 时,便更易于理解。