引子
有时候,你会发现,你的程序老是读不进某个值,但是反反复复看代码,又感觉自己代码真的没有问题。
比如说下面这个代码:
#include"stdio.h"
int main()
{
int num;
char ch;
scanf("%d",&num);
scanf("%c",&ch);
printf("%d%c",num,ch);
}
当你是以按回车表示结束输入完一个值时,你会发现,你只能输入一个值,然后程序就结束了。
你要改成这样:
#include"stdio.h"
int main()
{
int num;
char ch;
scanf("%d\n",&num);
scanf("%c",&ch);
printf("%d%c",num,ch);
}
或者是这样才行:
#include"stdio.h"
int main()
{
int num;
char ch;
scanf("%d",&num);
getchar();
scanf("%c",&ch);
printf("%d%c",num,ch);
}
当输入一个整型数据或者是浮点型数据时,残余的空格或者是回车会影响后面字符的读入。
为什么会这样?
原因是因为键盘输入流的缓冲效应。
我们先来讲一下I/O流。
I/O流
所谓流,简单来说,就像是一个接一个的数据按先进先出的顺序排成的数据流。基于字符的输入输出都是以流的方式进行的,像从键盘敲入的ASCII字符。每输入一个新字符,该字符就会被添加到流的尾部。
缓冲区
键盘输入的数据不会立即存储到相应变量中,而是先放到系统的一个缓冲区里面,每输入一个新数据,该新来的就会被放到输入流尾部,直到输入回车符作为一种确认结束输入,缓冲区里面的数据会被读入到相应变量的存储位置,之后系统会清空缓冲区。
所以在第一个程序中,在输入整型数据后,如果输入空格或者是回车会被放到缓冲区里面,那么字符型变量就会从缓冲区中读取空格或者是回车,然后程序结束。
所以一般需要用getchar()去吞掉一个回车,在C语言中,有时候也可以通过在前一个控制输入格式末尾加\n解决,但有时候只能用getchar()解决。
缓冲区的好处
正因为键盘输入的数据不会立即存储到相应变量中,而是先放到缓冲区中,因此,当输入错误字符想要删改的时候,可以通过退格键(backspace)或删除键(delete)删掉重新输入。
受系统影响
在Windows下,下面这个程序,会先输出a,过5秒后再输出b。
#include"stdio.h"
#include"unistd.h"
int main()
{
putchar('a');
sleep(5);
putchar('b');
putchar('\n');
}
其中sleep函数(要包含头文件unistd.h)是暂停程序执行,暂停时间由sleep参数决定,单位为秒。
但是在Linus下,a并不会立即输出,而是等过了五秒后和b一起输出。这是因为只有字符'\n'才能清空输出缓冲区,然后将字符序列添加到输出流中。