stringstream流操作时 .clear() 与 .str("")的使用

##一、 
 首先,.clear()方法我第一次是在cin对象上使用的,cin.clear()是用来更改cin的状态标示符的,cin在接收到错误的输入的时候,会设置状态位good。如果good位不为1,则cin不接受输入,直接跳过。如果下次输入前状态位没有改变那么即使清除了缓冲区数据流也无法输入。所以清除缓冲区之前必须要cin.clear()。[1]
 类比的话,我想stringstream流应该也是一样的功能。
 但是stringstream流和cin流还是有不同的,stringstream流好像是一个文件,而且好像有自己的读写位置指针,stringstream流有str()成员,而cin无此成员;

#include
#include
#include

using namespace std;
int main()
{
    string str;
    while(getline(cin, str)){
        //cout << cin.str() << endl; 错误,无此成员;
        vector<int> v, w;
        stringstream ss(str); //③
        int inter;
        char ch;
        while (ss >> inter)  //①
        {
            v.push_back(inter);
            ss >> ch;
        }
        ss.clear(); //
        ss.str("");  //!!在这儿清空一下ss流!!!!,不清空的话会导致下面的继续读入出现问题;

        getline(cin, str);
        ss.clear();
        ss << str;
        cout << "str本身的值是:" << ss.str() << endl;
        while(ss >> inter){ //②
            cout << inter;
        }

    }

    return 0;
}
输入:
1,2
3 4
输出:
str本身的值是:3 4
34

如果我们把ss.str(""); 这句注释掉,输出为:

输入:
1,2
3 4
输出:
str本身的值是:3 4

我们还是注释掉ss.str(""),但是更改一下输入:

输入:
1,2
3 4 5
输出:
str本身的值是:3 4 5
5

这说明什么?说明ss流在标号①处的while循环之后,其读指针(从流中读)已经在流开始的第2个位置处(从0位置开始数),而我们流的初始化时使用的stringstream ss(str)的方式,其写指针(写到流中)还是在流的开头,当我们写入的两个数据时,即还并没有在读指针的位置写下有效数据,所以标号②的输出为空,当我们写入三个数据,即在读指针的位置处写下数字5,输出:5。

所以
1)我们在使用流时,要注意读写指针的位置,一个比较好的习惯是,在创建流之后, 不进行标号③处的初始化,而是拆分为两条语句:

stringstream ss;
ss << str;

这样的话,写指针的头部在写完数据之后到了数据尾,读完之后,读指针也在数据尾,在下一次写入时是从数据尾的位置写入,而读指针此时刚好在新写入的位置处,就不会有稀奇古怪的问题发生了。
2)如果发生了问题,我们就要去思考是读写指针出现了问题,首先我们记得要先 .clear(),来设置good位,否则的话,流不是再次进行读写,其实,我们需要将 流 清空,使用 .str(""),即将流变成了一个类似于新创建的干净的流,我们再使用 << (写 流 操作)或者 >>(读 流 操作)时都不会出问题了。
3) 即使标号①处跳出了循环,此时你再次使用ss.str(),会发现会输出值:1,2,即,stringstream和cin不同,它并不清空流中的数据 ,只是在移动读写指针而已。

##二、与之类似的还有 .ignore方法;

  cin.ignore(a,ch);//忽略a个字符或者ch字符(包括ch)之前的字符;

从输入缓冲去中提取字符,提取的字符被忽略,不被使用。每抛弃一个字符,它都要计数和比较字符,如果计数值达到a或者被忽略的字符是ch,则cin.ignore()函数终止执行。默认参数是a=1,即仅忽略缓冲区中的第一个字符。它的一个常用功能是用来清除以回车结束的输入缓冲区的内容,消除上一次输入对下一次输入的影响。比如cin.ignore(1024,’\n’),通常把第一个参数设置得足够大,这样实际上总是只有第二个参数起作用,所以这一句就是把回车(包括回车)之前的所有字符从输入缓冲区中清除。[1]
  .ignore()这个方法我第一次使用是cin.ignore(),来消除上一次的输入的影响,因为cin在遇到\n终止时,并不清除缓冲区中的\n,这样如果下一次使用getline的话,会导致getline读到的数据是\n,那么getline就无法读到需要的数据,所以在getline之前需要加一句cin.ignore()来清除缓冲区中的\n。
  所以烦人的是cin在终止是竟然不清除最后的\n,我做了测试,getline在读到\n时,停止读入,并且清除最后的\n,即先使用getline,然后接着使用cin是不会出错的,但是,先使用cin,再使用getline会出错,原因就如前面所讲。
  
参考:
[1] cin的用法及清空输入缓冲区问题
[2] stringstream 的.str()正确用法和清空操作
[3] stringstream clear与str("")的问题

你可能感兴趣的:(C/C++编程语言)