前言
本文将以简单的代码介绍getchar(), putchar() 和 EOF 。
代码1
#include <stdio.h>
int main(void)
{
int c;
c = getchar();
putchar(c);
return 0;
}
运行结果如下:
键盘输入:abcdefg
屏幕输出:a(无换行,所以我的用户名和电脑名直接跟在运行结果后面了)
定义
getchar()
- “getchar() reads the next input character from a text stream and returns that as its value”
- “the characters normally come from the keyboard”
- 字符还可以来源于文本,但是不常见。
putchar()
- “putchar() prints a character each time it is called.”
- “putchar( c )” prints the contents of the variable c as a character."
注意
- getchar()的字符直接来源于 "a text stream"而不是键盘,虽然这些字符是从键盘输入的。
- putchar()只是把ch的内容以字符的形式打印出来,不会自动换行。
疑问
问题1.
定义里面说getchar()返回的是一个字符,那为什么ch的数据类型是int ?
答案:
- 先看getchar()的函数原型:
int getchar(void);
getchar()返回的数据类型就是int,所以ch定义为int是对的。但是疑问还在,getchar()返回的是一个character,为什么不使用char呢?请继续往下看。
问题2.
只输出了a,那么bcdefg去哪里了?请看代码2.
代码2
#include <stdio.h>
int main(void)
{
char ch;
ch = getchar();
/* 遇到回车符停止输出 */
while ('\n' != ch) {
putchar(ch);
ch = getchar();
}
return 0;
}
运行结果:
可以看出,getchar()一次只获取一个字符,但是键盘输入的其他字符也没有被丢弃。继续使用getchar()可以取出后面的字符。
这种输入叫“缓冲输入”,键盘输入的数据会先存入缓冲区,当你按下回车键后,getchar()才会从缓冲区获取一个字符。
与之对应的是无缓冲输入。想想我们玩的游戏,比如射击游戏里面的“w(前进)”“a(左移)”“s(后退)”“d(右移)”,我们一旦按下去就会生效,而不是按下w键后还要按回车键。这里w键一旦输入就被游戏程序读走,而不能再先存入缓冲区再被读走。
但是代码2却存在一个问题,要是我需要在屏幕上输出一个换行符呢?一种方法就是将while的循环条件里面的’\n’换成其他字符x(x代表其他字符),但要是需要输出x呢?
有没有能输出任意字符的写法呢?请看代码3。
代码3
#include <stdio.h>
int main(void)
{
int ch;
ch = getchar();
while (EOF != ch) {
putchar(ch);
ch = getchar();
}
return 0;
}
运行结果:
这次进行了五次输入,三次输入了字母,两次是输入了回车键,但是程序还是没有退出。
注意
在这种情况下,键盘输入任意字符(不能是特殊组合键),程序都不会退出。说明EOF不是我们用到的任何字符。
那EOF是什么呢?
我们先看看字符有哪些呢?
字符的数据类型是char,char长度一般为8bits,8位可表示的数值范围为2^8=256(即0~255)。
目前我们计算机用到的字符都包含在0~255这个范围了。
所以,只要在这个范围外,都可以替代EOF,代码3的功能不变。可以用一个负数或任意大于255的数来替换EOF.
解释
EOF相关描述:
EOF:
- a value that cannot be confused with any real character. this value is called EOF, for “end of file”
- EOF is an integer defined in <stdio.h>, but the specific numeric value does not matter as long as it is not the same as any char value.
第2个描述指出,EOF是一个整数,且说EOF具体数值其实不重要,重要的是它不能和任意字符相同。
虽然这样说,但我还是想看看EOF是什么数值?
方法一:既然是整数,那就可以打印出来看看
#include <stdio.h>
int main(void)
{
printf("EOF = %d\n", EOF);
return 0;
}
运行结果:
方法二:查看stdio.h文件
EOF定义的数值是"-1",不属于0~255这个范围。
注意
EOF的第1个描述中“for “end of file””
stdio.h文件中注释“The value returned by fgetc and similar functions to indicate the end of the file.”都说EOF代表文件结束的意思。这又是怎么回事呢?
问题出在getchar()上,getchar()不断从输入(内存)中按字节读取数据,那就要知道输入什么时候结束(读取到哪个位置)。
如果数据是从文件中输入的,那么getchar就需要知道文件内容在位置x处结束,不能再继续往下读取数据了。比如:我们的stdio.h文件,我们看着是一个文件,其实就是内存中的一段内存,我们读取里面的内容,只能从开头读取到结尾,不能多读,否则就是非法访问了。指针的非法使用会造成很多意想不到的问题。
如果是从键盘输入,大多数的系统都有办法模拟文件结束的条件。
所以,当getchar()读取数据的时候,正常情况下,返回的是读取的字符,一旦检测到输入的结束(文件结束或键盘输入结束),getchar()就会就不再读取数据了(此时不能再读了),所以它需要返回一个与任何字符不一样的整数(getchar()返回数据类型为int),来告诉调用它的程序已经读完了。
注意
EOF并不是getchar()在检测到输入结束时读取到的值,而是getchar()检测到输入结束的时候直接返回的一个值,之前返回的值的确是读取到的字符,此时的值是用来代表“已经读取到输入结束的位置了”。
看代码:
#include <stdio.h>
int main(void)
{
int ch;
ch = getchar();
while (EOF != ch) {
putchar(ch);
ch = getchar();
}
return 0;
}
运行结果:
这里输入“EOF”还是“-1”,程序都不会退出。别忘了,getchar()是按字符读取数据的,看着输入EOF,其实getchar()分三次依次返回“E”,“O”,“F”,同样需要两次依次返回“-”和“1”。
这里,也就知道getchat()返回的“-1(即EOF)”一定不可能是读取到的.
因为getchar()不仅会返回字符也会返回整数,所以getchar()的返回值的数据类型采用int也就没毛病了。
阅读摘抄
PREP是一种“结论先行”的沟通法则。
P: point (结论)
R: reason (依据)
E: example (具体事例)
P: point (重申结论后结束)
ps:报告,日常邮件、说话、回答问题、会议推进等,都应该遵循PREP模式,结论先行。