对标题和序号稍加修改。
8.1 缓冲区
输入分为无缓冲输入和缓冲输入。无缓冲输入即回显用户输入的字符后立即重复打印该字符。缓冲输入即在按下Enter键前不会重复打印输入的字符。缓冲区(buffer)是储存用户输入字符的临时存储区,在按下Enter键后程序才能使用输入的字符。缓冲区大小取决于系统,常见大小为512字节或4096字节。
缓冲分为完全缓冲I/O和行缓冲I/O。完全缓冲I/O指当缓冲区被填满时才刷新缓冲区,即把数据发送到屏幕或文件中,常用于文件输入。行缓冲I/O指遇到换行符时刷新缓冲区,常用于键盘输入。
C标准明确规定了当缓冲区满、遇到换行字符或需要输入的时候刷新缓冲区。旧式编译器遇到scanf()
也不会强行刷新缓冲区,程序会停止并不显示任何提示内容,等待用户输入数据,此情况下可以用转义字符\n
刷新缓冲区。
ANSI C和后续C标准都规定输入是缓冲的,ANSI没有提供无缓冲的标准方式。
8.2 结束键盘输入
8.2.1 文件、流和键盘输入
文件(file)是存储器中储存信息的区域。较低层面,C用底层I/O(lower-level I/O)处理文件。较高层面,用标准I/O包(standard I/O package)处理文件。
流(stream)是一个实际输入或输出映射的理想化数据流。C通过处理流来处理文件,打开文件就是将流与文件关联,读写通过流来完成。
stdin流表示键盘输入,stdout表示屏幕输出。标准I/O成员getchar()
、putchar()
、scanf()
和printf()
用来处理两个流。
8.2.2 文件结尾
检测文件结尾的两个方法:
- 使用特殊标记,例如Ctrl+Z。
- 储存文件大小的信息。
C语言输入函数内置了文件结尾检测器,当输入函数读取文件检测到结尾时就返回EOF(end of file),它被定义在stdio.h
中。
#define EOF (-1)
示例程序:
#include<stdio.h>
int main(void)
{
int ch;
while ((ch=getchar())!=EOF)
putchar(ch);
return 0;
}
输出结果:
abcdefg
abcdefg
123
123
!@#$
!@#$
^Z
每次按Enter都会刷新缓冲区,将输入的内容在下一行打印出来,直至在新行中键入Ctrl+Z,才结束键盘输入。
8.3 创建更友好的用户界面
8.3.1 使用缓冲输入
示例程序:
/*猜数字*/
#include<stdio.h>
int main(void)
{
int guess=1;
char response; //存储响应字符,每行第一个字符
printf("Pick an integer from 1 to 100.I will try to guess it.\n");
printf("Respond with y if my guess is right"
" and with n if it is wrong.\n");
printf("Uh...is your number %d?\n",guess);
while ((response=getchar())!='y') //每次只读每行第一个字符
{
if (response=='n')
printf("Well,then,is it %d?\n",++guess);
else
printf("Sorry, I understand only y or n,"
" press n to continue.\n");
/*处理读取每行第一个字符后的所有输入字符,包括回车产生的换行符*/
while (getchar()!='\n')
continue;
}
printf("Done!\n");
return 0;
}
输出结果:
Pick an integer from 1 to 100.I will try to guess it.
Respond with y if my guess is right and with n if it is wrong.
Uh...is your number 1?
n
Well,then,is it 2?
no sir
Well,then,is it 3?
forget it!
Sorry, I understand only y or n, press n to continue.
n
Well,then,is it 4?
y
Done!
8.3.2 混合数值和字符输入
示例程序:
/*按指定行列打印字符*/
#include<stdio.h>
void display(char cr, int lines, int width); /*函数原型*/
int main(void)
{
int ch; /*待打印字符*/
int rows,cols; /*行数和列数*/
printf("Enter a character and two integers:\n");
while ((ch=getchar())!=EOF) /*EOF结束键盘输入*/
{
/*没有正确读取行和列数就退出循环*/
if (scanf("%d %d",&rows,&cols)!=2)
break;
/*正确读取行和列数就调用函数*/
display(ch,rows,cols);
/*跳过输入中剩余的多余项*/
while (getchar()!='\n')
continue;
printf("Enter another character and two integers:\n"
"Press Ctrl+Z to quit.\n");
}
printf("Done!\n");
return 0;
}
/*函数定义*/
void display(char cr, int lines, int width)
{
int row,col;
for (row = 1; row <= lines; row++)
{
for (col = 1; col <= width; col++)
putchar(cr);
putchar('\n');
}
}
输出结果:
Enter a character and two integers:
c 1 2
cc
Enter another character and two integers:
Press Ctrl+Z to quit.
! 3 6
!!!!!!
!!!!!!
!!!!!!
Enter another character and two integers:
Press Ctrl+Z to quit.
^Z
Done!