短语输入输出流类可以看 C++一些常识.md
stringstream 对象在使用 >> 运算符或者 getline 函数时,都会移动输入指针,而不是简单地复制或删除数据。在使用 getline 函数时,它会从当前位置开始读取数据,直到遇到指定的分隔符或文件结束符为止。
string s,k;
stringstream ss("asdfg tgyh 123;");
getline(ss,s);
getline(ss,k);
cout<<k;//这里k是空的,因为第一次调用getline已经把输入指针放到字符链的末尾了,在次调用当然读取不到!
又比如说:
string s,k;
stringstream ss("asdfg tgyh 123;");
ss>>s;//s=="asdfg",因为用>>取流中内容时,以空格为结束符,现在输入指针到了下一个字符即空格处。
getline(ss,k);//getline包容除结束符之外一切字符,所以k==" tgyh 123;"
cout<<k;
如果非要将指针返回到指定位置(例如开头),有一种方法(在这之前先看解释)
//如果输入时产生错误状态 , 其中之一是EOF(End Of File),则先清除错误状态,在用seekg方法移动指针
//如果没有产生错误状态,直接调用seekg方法即可
//以下为解释为什么会有输入错误状态:
/*因为在读取数据时可能会遇到一些错误。常见的错误包括:
1.输入的数据类型与预期的不符(例如,期望读取一个整数,但输入的却是一个字符串);
2.输入的数据格式不正确(例如,期望读取一个数字,但输入的字符串中包含非数字字符);
3.输入流遇到文件末尾或读取失败。
当输入流对象出现错误时,它的状态位会被设置,表示输入操作失败。此时,如果不清除错误状态,再次进行输入操作时就可能出现问题。因此,在读取数据之前,通常需要使用 cin.clear() 方法清除输入流对象的错误状态。
此外,有些输入操作(例如 getline 函数)可能会留下未读取的字符,导致输入指针位置不正确。在这种情况下,我们可以使用 cin.ignore() 方法跳过这些未读取的字符,或者使用 cin.seekg() 方法将输入指针移动到正确的位置。*/
如果要从 stringstream 的开头开始读取数据,可以先使用 seekg 方法将指针移动到开头的位置。
情况一:没有错误状态
stringstream strm("hello world");
string line1, line2;
getline(strm, line1); // line1 = "hello world"
strm.seekg(0); // 将输入指针移回到起始位置
getline(strm, line2); // line2 = "hello world"
//第一次调用getline没有产生错误状态,并不是因为strm流中没有结束符(默认为\n'),就算有,getline也会将结束符从缓冲区提取出来丢掉,这是正确的状态
情况二:数据类型冲突的错误状态
stringstream stream;
int a, b,c;
stream<<"80 f";
stream >> a>>b; //相当于stream>>a; stream>>b;
cout << "a = " << a << endl; //a=80
cout << "b = " << b << endl; //b=0; 第二次先识别到空格,无效,继续往后提取到f, 数据类型不对, b=0,产生错误
stream.str(""); //用于清空stream流内容
stream<<"1234";
stream>>c; //仍然为0,因为第二次的错误状态没有被清除
(//b=0, 过程是这样的,第一次成功解析80赋予a, 第二次先识别到空格,无效,继续往后提取到f, 数据类型不对,产生错误
情况二的改正:
//在第二次输入后,第三次输入前添加stream.clear(); 即可
//如果再添一笔
stringstream stream;
int a, b,c;
stream<<"80 f";
stream >> a>>b; //相当于stream>>a; stream>>b;
cout << "a = " << a << endl; //a=80
cout << "b = " << b << endl; //b=0; 第二次先识别到空格,无效,继续往后提取到f, 数据类型不对, b=0,产生错误
stream.clear(); //清除错误状态
stream.str(""); //用于清空stream流内容
stream<<"1234";
stream.seekg(2); //指定指针位置
stream>>c; //c=34;
情况三 读取到尽头的错误(EOF)
stringstream stream;
int a,b;
stream<<"80";
stream>>a; //stream 读取到尽头,产生EOF错误
stream<<"90"; //stream内容变为8090,但是指针位置在第一次末,如果正常应该读取90给b, 但是需要清除错误
stream>>b;
cout<<a<<endl;
cout<<b<<endl;
情况三解决
//在第一次后加stream.clear(); 即可
需注意的点
用seekg移动指针是指在同一个流状态,例如
stream<<"80 f";
stream >> a>>b; //相当于stream>>a; stream>>b;
cout << "a = " << a << endl; //a=80
cout << "b = " << b << endl; //b=0; 第二次先识别到空格,无效,继续往后提取到f, 数据类型不对, b=0,产生错误
stream.clear(); //清除错误状态
stream.str(""); //用于清空stream流内容
stream<<"1234";
stream.seekg(2); //指定指针位置
stream>>c;
当重置了stream为"1234", 指针会自动移动到起始。
一个问题 stringstream的上述规则不适用于cin;
tring s,k;
getline(cin,s);
cin.clear();
cin.seekg(0);
getline(cin,k);
cout<<"s="<<s<<endl;
cout<<"k="<<k<<endl; //k仍然是空的
代码中,你调用了 cin.clear() 来清除 cin 的错误状态,但是这并不会影响输入缓冲区中的数据,所以在调用 getline(cin, k) 时,因为缓冲区中已经没有数据了,所以 k 仍然是空的。
std::stringstream 是一个内存中的字符串流,它将一个字符串作为缓冲区,并在其中执行输入和输出操作。因此,在执行第二个 getline 时,而对于 cin,它通常是一个从命令行或终端读取输入的输入流,它在执行第二次 getline 时需要重新定位到开头,因为输入流通常只能被读取一次。