文章目录
字符输入/输出
了解C语言的输出输入首先要了解几个概念,输入输出,标准文件,缓冲等。
I/O(输入/输出)
- 输入(input):向程序填充一些数据。
- 输出(output):在屏幕上、打印机上或任意文件中显示一些数据。
标准文件
文件是存储器中储存信息的区域。通常,文件都保存在某种永久存储器中(如,硬盘、U盘或DVD等)。
C 语言把所有的设备都当作文件。所以设备被处理的方式与文件相同。
从较低层面上,C可以使用主机操作系统的基本文件工具直接处理文件,这些直接调用操作系统的函数被称为底层 I/O。
从较高层面上,C还可以通过标准I/O包来处理文件。
流
从概念上看,C程序处理的是流而不是直接处理文件。流是一个实际输入或输出映射的理想化数据流。这意味着不同属性和不同种类的输入,由属性更统一的流来表示。于是,打开文件的过程就是把流与文件相关联,而且读写都通过流来完成。
- stdin流:标准输入流,一般默认对应键盘设备文件。
- stdout流:标准输出流,一般默认对应显示器设备文件。它从标准输入文件中得到输入数据,将正常输出数据输出到标准输出文件。
- stderrr流:标准错误流,一般默认对应显示器设备文件。它将错误信息输出到对应的标准错误文件。
缓冲
- 无缓冲输入:回显用户输入的字符后立即重复打印该字符属于无缓冲输入。
- 缓冲输入:大部分系统在用户按下Enter键之前不会重复打印刚输入的字符,这种输入形式属于缓冲输入。
注:
- 虽然大部分情况下都用缓冲输入,但是无缓冲输入也是必要的,毕竟你也不希望你玩游戏或者看电视的时候,按一个按键没反应吧。
- ANSI没有提供调用无缓冲输入的标准方式,这意味着是否能进行无缓冲输入取决于计算机系统。
缓冲分为两类:
- 完全缓冲:完全缓冲输入指的是当缓冲区被填满时才刷新缓冲区(内容被发送至目的地),通常出现在文件输入中。
- 行缓冲:在出现换行符时刷新缓冲区。键盘输入通常是行缓冲输入,所以在按下Enter键后才刷新缓冲区。
缓冲区(buffer)
用户输入的字符被收集并储存在一个被称为缓冲区的临时存储区,按下Enter键后,程序才可使用用户输入的字符。
作用
- 把若干字符作为一个块进行传输比逐个发送这些字符节约时间。
- 如果用户打错字符,可以直接通过键盘修正错误。当最后按下Enter键时,传输的是正确的输入。
I/O函数
scanf()和printf()
printf()是输出函数,scanf()是输入函数,两个函数都使用格式字符串和参数列表。前面有文章专门介绍了这两个函数,这里不展开。
单字符I/O:getchar()和putchar()
- getchara(): 函数从键盘读取下一个可用的字符。这个函数在同一个时间内只会读取一个单一的字符。可以在循环内使用这个方法,以便从屏幕上读取多个字符。
- putchar():函数把字符输出到屏幕上,并返回相同的字符。这个函数在同一个时间内只会输出一个单一的字符。可以在循环内使用这个方法,以便在屏幕上输出多个字符。
由于这些函数只处理字符,所以它们比更通用的scanf()和printf()函数更快、更简洁。而且,注意 getchar()和 putchar()不需要转换说明,因为它们只处理字符。这两个函数通常定义在 stdio.h头文件中。
示例
#include <stdio.h>
#define SPACE ' '
int main(void)
{
char ch;
ch = getchar();
while (ch != '\n')
{
if (ch == SPACE)
putchar(ch);
else
putchar(ch + 1);
ch = getchar();
}
putchar(ch);
return 0;
}
解释
ch=getchar();读取一个字符并赋值给ch变量,利用while循环不断读取字符,如果读入的字符是一个空格,那么将会保留这个空格(putchar()将读到的ch输出),否则输出此字符下一个字符。
gets( )和puts()函数
- gets():从键盘上输入字符,直至接受到换行符或EOF时停止,并将读取的结果存放在buffer指针所指向的字符数组中。
- puts():函数将字符输出到屏幕。
注意:gets函数由于没有指定输入字符大小,所以会无限读取,一旦输入的字符大于数组长度,就会发生内存越界,从而造成程序崩溃或其他数据的错误。
注意混用问题
假设程序要求用 getchar()处理字符输入,用 scanf()处理数值输入,这两个函数都能很好地完成任务,但是不能把它们混用。因为 getchar()读取每个字符,包括空格、制表符和换行符;而 scanf()在读取数字时则会跳过空格、制表符和换行符。
#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()) != '\n')
{
scanf("%d %d", &rows, &cols);
display(ch, rows, cols);
printf("Enter another character and two integers;\n");
printf("Enter a newline to quit.\n");
}
printf("Bye.\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');
}
}
解释
该程序开始时运行良好。但当输出完第一组数据时,程序直接退出了,这是输入行中紧跟在 后面的换行符。scanf()函数把这个换行符留在输入队列中。和 scanf()不同,getchar()不会跳过换行符,所以在进入下一轮迭代时,你还没来得及输入字符,它就读取了换行符,然后将其赋给ch。而ch是换行符正式终止循环的条件。
解决方法
while (getchar() != '\n')
continue;
可以使用while循环处理掉scanf()输入后面所有字符,为循环的下一轮读取做好了准备。
改正后,如下:
#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()) != '\n')
{
if (scanf("%d %d", &rows, &cols) != 2)
break;
display(ch, rows, cols);
while (getchar() != '\n')
continue; //处理scanf剩余字符,包括换行符
printf("Enter another character and two integers;\n");
printf("Enter a newline to quit.\n");
}
printf("Bye.\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');
}
}
}
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');
}
}