1、I/O函数
前几章简单介绍过这类函数,不知道大家是否还有印象,如printf()、scanf()、getchar()、putchar()等。这些函数负责把信息传送到程序中。为了帮助大家回忆这些函数的工作方式,请简单学习以下程序。该程序获取从键盘输入的字符,并把这些字符发送到屏幕上。程序使用while循环,当读到#字符时停止。
#include <stdio.h>
int main(void)
{
char ch;
while ((ch = getchar()) != '#')
putchar(ch);
return 0;
}
输出结果如下:

缓冲区的概念
对于该例,大部分系统在用户按下Enter键之前不会重复打印刚输入的字符,这种输入形式属于缓冲输入。用户输入的字符被收集并存储在一个被称为缓冲区(buffer)的临时存储区,按下Enter键后,程序才可使用用户输入的字符。
为什么要有缓冲区?首先,把若干字符作为一个块进行传输比逐个发送这些字符节约时间。其次,如果当你打错字符,可以直接通过键盘修正错误。当最后按下Enter键时,传输的是正确的输入。虽然缓冲输入好处很多,但是也有很多交互式程序需要无缓冲输入。例如,在你打游戏的时候,你希望按下一个键就执行相应的指令。所以在程序中缓冲输入和无缓冲输入没有绝对的好与坏之分。
文件结尾
计算机操作系统要以某种方式判断文件的开始和结束。检测文件结尾的一种方法是,在文件末尾放一个特殊的字符标记文件结尾。
无论操作系统实际使用何种方法检测文件结尾,在C语言中(Linux的Shell脚本中),用getchar()读取文件检测到文件结尾时将返回一个特殊的值,即EOF(End Of File的缩写)。scanf()函数检测到文件结尾时也返回EOF。通常,EOF定义在stdio.h文件中:
#define EOF (-1)
之所以是-1?因为getchar()函数的返回值通常都介于0~127,这些值对应标准字符集。但是,如果系统能识别扩展字符集,该函数的返回值可能在0~255。所以无论什么情况,-1都不对应任何字符,所以,该值可用于标记文件结尾。
注意:
不用考虑定义EOF,因为stdio.h中已经定义过了。
不用考虑EOF的实际值,因为EOF在stdio.h中用#define预处理指令定义,可直接调用。
输入验证
在实际应用中,用户不一定会按照程序的指令行事。用户的输入和程序期望的输入不匹配时常发生,这会导致程序运行失败。作为程序员,除了完成编程的本职工作,还要事先预料一些可能的输入错误,这样才能编写出能检测并处理这些问题的程序。
程序案例:
假设你编写了一个处理负数整数的循环,但是用户很可能输入一个非负数。你可以使用关系表达式来排除这种情况:
long n;
scanf("%ld", &n); // 获取第1个值
while (n <= 0) // 检测不在范围内的值
{
scanf("%ld", &n); // 获取下一个值
}
另一类潜在的陷阱是,用户可能输入错误类型的值,如字符q。排除这种情况的一种方法是,检查scanf()的返回值。回忆一下,scanf()返回成功读取项的个数。因此,下面的表达式当且仅当用户输入一个整数时才为真:
long n;
while (scanf("%ld", &n) == 1 && n <= 0)
{
}
while循环条件可以描述为“当输入是一个整数且该整数为负数时”。
简而言之,输入由字符组成,但是scanf()可以把输入转换成整数值或浮点数值。使用转换说明(如%d或%f)限制了可接受输入的字符类型,而getchar()和使用%c的scanf()接受所有的字符。