stringstream坑点及具体解释

短语输入输出流类可以看 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 时需要重新定位到开头,因为输入流通常只能被读取一次。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值