C++字符串输入缓冲区机制详解
一、缓冲定义
1.缓冲定义
缓冲是在两种不同速度设备之间传输信息时平滑传输过程的常用手段。
2.为什么引入缓冲区
操作系统这门课有明确的说明缓冲的作用,是为了解决高速设备和低速设备之间速度不匹配的问题,直接举个书上的CPU和打印机的例子:
首先我们要用打印机打印一篇文章肯定要经过CPU处理然后给到打印机打印文章,但是CPU处理1000个字节的文字一眨眼的事情,但是打印机可能需要若干秒,总不可能让CPU处理一个数据给打印机一个数据这样子等着运行,这就引入了缓冲区,CPU处理完数据存入缓冲区,打印机直接从缓冲区提取已经处理好的数据,这样子就解决了高速设备(CPU)和低速设备(打印机)处理速度不匹配的问题。
二、scanf,cin输入缓冲区
1.scanf和cin的缓冲类型
scanf和cin的缓冲类型为行缓冲,行缓冲的的特点是在输入数据只要没有碰到换行符(回车)就将数据存入输入缓冲区,当碰到换行符之后就将缓冲区中的数据取出使用。
2.scanf和cin的缓冲机制
scanf和cin输入数据缓冲机制基本一致,在读入一个数据时直到回车之前他都会存储在输入缓冲区中,直到碰到回车才会将数据从输入缓冲区中取出供变量使用,但是缓冲区中的换行符会被留在输入缓冲区中。
3.cin.getline和cin.get
cin.get读取字符串直到读取到回车为止,但是也会将回车留在缓冲区。
cin.getline读取字符串直到读取到回车为止,但是不会讲回车留在缓冲区。
4.scanf和cin输入
①cin和scanf读取一个字符的区别
char c; cin>>c;//cin读取字符的时候不会读入空格、回车以及制表符,如果缓冲区开头是换行符或者制表符会被忽略并清除 scanf("%c",&c);//scanf读取字符的时候不会管你是什么字符直接读进来
②cin和scanf在读取缓冲区中的数字、字符串、浮点型的时候不会将开头的空格、换行符或者制表符当作数据读入,如果碰到了他们会将它们忽略并清除。需要注意cin.get和cin.getline不会将开头的空格、换行符或者制表符忽略并删除。
5.可能遇到的问题
①在用cin或者scanf读取一个字符串之后scanf再读取一个字符,发现读取的字符没办法输入而且输出了一个回车。看如下代码:
char name[20]; char c; cin>>name; cout<<name<<endl; scanf("%c",&c); cout<<"---"<<int(c)<<endl;
结果如下截图:
当我们输入name为123的时候程序就结束了输出c的值为10,在ASCII码编码中10对应的是换行符,为什么会出现上述这种情况呢?因为cin输入完之后将回车保留在了缓冲区中,而scanf("%c",&c)输入字符并不会判断是空格还是回车,直接将缓冲区中的回车拿了出来给了字符变量c。
②用cin.getline输入字符串之后再用scanf读取一个字符就和上面不一样了。看如下代码:
char name[20]; char c; cin.getline(name,20); cout<<name<<endl; scanf("%c",&c); cout<<"---"<<int(c)<<endl;
结果如下截图:
结果不同的原因是因为scanf,cin,cin.get在行缓冲取出数据之后会将换行符留在缓冲区中,然后再用scanf读入一个字符发现缓冲区并不为空就从缓冲区中将数据拿出来,而cin.getline会将缓冲区中的换行符也清除,所以不会有①这种情况出现。
③读入一个字符串之后后面的cin.get()一直无法读取数据,看如下代码:
char name[20]; cin.get(name,20); cout<<"--"<<name<<endl; cin.get(name,20); cout<<"--"<<name<<endl; cin.get(name,20); cout<<"--"<<name<<endl; cin.get(name,20); cout<<"--"<<name<<endl; cin.get(name,20); cout<<"--"<<name<<endl;
结果如下截图:
可以看到用第一个cin.get输入了数据之后后面的cin.get都无效了,这是因为cin.get从缓冲区中读取到换行符就结束并将换行符保留在缓冲区中,接下来的cin.get一直在缓冲区中碰到换行符就一直没有实际数据输入。
④整形和字符串混合输入
当先输入一个整形再用cin.getline输入字符串会发现没有经历输入字符串的过程,测试如下代码:
char name[20]; int a; cin>>a; cout<<a<<endl; cin.getline(name,20); cout<<"---"<<name<<endl; cout<<"end"<<endl;
结果如下:
根据上面的缓冲原理比较容易理解,cin输入一个整形后会在缓冲区中留下一个换行符,因为缓冲区中有换行符剩余,cin.getline从缓冲区中取出数据发现正好是换行符,那么就默认字符串输入完了,并将换行符从缓冲区中去掉,所以造成了上面的局面。
清除缓冲区
上面讲的问题基本上都是因为缓冲区中剩余的数据造成的,那么只需要有方法清除缓冲区就行了,可以用getchar(),cin.get()读取缓冲区中多的换行符。