K&R C编程语言1.5.1(文件复制)

好吧,我几个月前读过另一本“知名”的C书(用我的语言),我从来没有学到这一点。 K&R在20页中写出3章的方式简直令人惊叹,当然我不能指望大量的解释,但这也会引发问题。

我对这一点有疑问1.5.1这本书说(第16页):

main(){ int c;// <-- Here is the question c=getchar(); while (c != EOF){ putchar(c); c = getchar(); } } 

[…] char类型专门用于存储此类字符数据,但可以使用任何整数类型。 我们使用int是一个微妙但重要的原因。 问题是区分输入结束和有效数据。 解决方案是,当没有更多输入时,getchar会返回一个独特的值,这个值不能被任何真实字符所包含。 对于“文件结束”,该值称为EOF。 我们必须声明c是一个很大的类型,可以保存getchar返回的任何值。 我们不能使用char,因为除了任何可能的char之外,c必须足够大以容纳EOF。 因此我们使用int。[…]

在谷歌搜索另一个解释后:

EOF是一个特殊的宏,表示文件结束(Linux:在键盘上使用CTRL + d来创建它,Windows命令:使用CTRL + z(可能必须在新行的开头,然后是RETURN)):通常EOF = -1,但依赖于实现。 必须是对任何可能的字符都不是有效值的值。 因此,c的类型为int(不是人们可能预期的char)。

所以我修改了从int到char的源代码,看看问题是什么,关于获取EOF值…但是没有问题。 以同样的方式工作。

我也没有不好意思,getchar如何处理我写的每个角色,并打印所有内容。 Int类型长度为4bytes,因此变量中可以包含4个字符。 但我可以放任意数量的字符,它会以相同的方式读写所有内容。 和char一样,发生了同样的事情……真的发生了什么? 当超过1-4个字符时,值存储在哪里?

所以我修改了从int到char的源代码,看看问题是什么,关于获取EOF值…但是没有问题。 以同样的方式工作

碰巧以同样的方式工作。 这一切都取决于char的真实类型,即它是签名还是未签名。 关于这个主题还有一个C FAQ 。 如果您的char未签名,您更有可能看到该错误。

但是,如果字符已签名且输入为全部7位字符,则该错误可能会长时间未被检测到。

编辑

最后一个问题是:char类型是一个字节长,int是4bytes长。 所以,char只会带一个ascii字符。 但是如果我输入“堆栈溢出超过1byte”,输出将是“堆栈溢出超过1byte”。 存储了“大头溢出超过1字节”的位置,putchar如何放置整个字符串

每个字符将依次由c存储。 所以第一次, getchar()将返回sputchar将在它的路上发送它。 然后t会出现,依此类推。 在任何时候都不会存储多个角色。 因此,虽然你喂它一个大字符串,它通过一次吃一个字符来处理它。

分为两个答案:

为什么int而不是char

简短而正式的答案:如果您希望能够表示所有真实字符和另一个非真实字符(EOF),则不能使用仅用于保存真实字符的数据类型。

可以理解但不完全准确的答案 :函数getchar()返回它读取的字符的ASCII代码或EOF。

因为-1转换为char等于255,我们无法区分255个字符和EOF。 那是,

 char a = 255; char b = EOF; a == b // Evaluates to TRUE 

但,

 int a = 255; int b = EOF; a == b // Evaluates to FALSE 

因此,使用char将不允许您区分ASCII码为255(从文件读取时可能发生)的字符和EOF。

为什么你可以使用int的putchar()

putchar()函数查看其参数,查看数字,然后转到ASCII表并绘制它看到的字形。 当你传递一个int ,它被隐式地转换为char 。 如果int的数字适合char ,一切都很好,没有人注意到任何东西。

如果使用char来存储getchar()的结果,则有两个潜在的问题,您将遇到的问题取决于char的签名。

  • 如果char是无符号的,则c == EOF将永远不会为真,您将获得无限循环。

  • 如果char已签名,则当您输入一些char时, c == EOF将为true。 这将取决于使用的charset; 在使用ISO8859-1或CP852的区域设置中,如果EOF为-1(最常见的值),则为’ÿ’。 某些字符集(例如UTF-8 (char)EOF在有效代码中不使用值(char)EOF ,但您很少能保证您的问题将保留在signed char实现上,并且仅用于非有问题的语言环境中。