c++ 输入与缓冲区

背景

对于程序而言,从键盘键入至程序读入,期间会将内容暂存在一个缓冲区中。代码的输入语句会直接从缓冲区中读取内容,所以有时候出现奇奇怪怪的意想不到的状况的时候,就是因为缓冲区也许留存有上一次的残留数据,导致被“错误读入”。
而且有些函数是对空格,回车不感冒,如cin,而有些却能够读取回车符如cin.get。下面就争对这些情况做个实验:

cin

cin 读取程序代码后面的对应的变量类型
结束标志:空格或者回车

cin 在读入之前, 会主动清空缓冲区中残余的空格或者回车.

// 输入:【enter1】【2】【空格】【空格】【c】【enter2】
int main() {
	int a;
	char b;
	cin >> a >> b;  // enter2 被留在缓冲区
	cout << a << b;
}
// 输出:
2 c

https://en.cppreference.com/w/cpp/io/cin

cin.getline()

先看一下函数定义:

getline 函数从一个输入流(input stream)读入字符,并append至 string

函数不断读入字符并 append 至 string,其结束条件为:

a) 输入流读到了一个文件的末尾。getline 设置 eofbit
b) 下一个读入的字符为 delim, 这种情况下读入 delim 之后就停止读入,且 delim 不会 append 至 string
c) string 长度已经到了 max_size

构造函数显示,getline 函数 传入的 input_stream 的引用。所以,返回传入的流引用本身

template< class CharT, class Traits, class Allocator >
std::basic_istream<CharT,Traits>& getline( std::basic_istream<CharT,Traits>&& input,
                                          std::basic_string<CharT,Traits,Allocator>& str );

template< class CharT, class Traits, class Allocator >
std::basic_istream<CharT,Traits>& getline( std::basic_istream<CharT,Traits>&& input,
                                           std::basic_string<CharT,Traits,Allocator>& str,
                                           CharT delim );

第一种用法就是 getline(input_stream, str) —— 此用法则默认 delim 是换行符
第二种是getline(input_stream, str, delim) —— 不断读入,除非遇到(a、b、c)情况

getline 函数不会主动清空缓冲区,即会读入 enter 空格。所以会出现读入“异常”的情况
比如:

// 测试输入1:【enter1】【5】【enter2】【7777】
int main()
{
	int a;
	cin >> a;
	
	string str;
	getline(cin, str);
	cout << str;  // 测试1:没有正确读入我们想要的 7777
}
// 输出1:
【enter】

原因就是输入的【enter2】残留在了输入缓冲区,而且默认delim是换行符
【enter2】被 getline 读入,结束输入

// 测试输入2: 【enter1】【5】【空格4444】【enter2】
// 输出2:
【空格4444】

【空格】不会被geline主动清空,所以依旧读入

// 测试3:【enter1】【5】【空格】【aaa】【enter2】【123x】
int main()
{
	int a;
	cin >> a;
	
	string str;
	getline(cin, str, 'x');
	cout << str;  // 测试1:没有正确读入我们想要的 7777
}
// 输出3
【空格aaa】【enter】【123】

我们主动添加了 delim='x' ,所以可继续读入 enter

解决getline的误读: cin>>std::ws

int a;
cin >> a;
	
string str;

cin >> std::ws;  // 解决残留的空格换行符
getline(cin, str);
	
cout << str;

如 cppreference 建议的,添加上 cin>>std::ws 即可

https://en.cppreference.com/w/cpp/string/basic_string/getline
http://www.augustcouncil.com/~tgibson/tutorial/iotips.html
http://www.augustcouncil.com/~tgibson/tutorial/UnderstandingComplexExpressions.pdf

上一篇:算法进阶(8): EM算法


下一篇:C++中getline函数的用法