stringstream

stringstream是 C++ 提供的另一个字串型的串流(stream)物件,和之前学过的iostream、fstream有类似的操作方式。要使用stringstream, 必须先加入这一行:

include <sstream>

tringstream主要是用在將一个字符串分割,可以先用.clear( )以及.str( )將指定字串设定成一开始的內容,再用>>把个別的资料输出。

举个例子:
題目:输入的第一行有一个数字 N 代表接下來有 N 行资料,每一行资料里有不固定个数的整数(最多20个,每行最大200个字元),编程將每行的总和打印出來。

输入:
3
1 2 3
20 17 23 54 77 60
111 222 333 444 555 666 777 888 999

输出:
6
251
4995


#include <iostream>
#include <string>
#include <sstream>
using namespace std;
 
int main()
{
    string s;
    stringstream ss;
    int n;
 
    cin >> n;
    getline(cin, s);  //读取换行
    for (int i = 0; i < n; i++)
    {
        getline(cin, s);
        ss.clear();
        ss.str(s);
 
        int sum = 0;
 
        while (1)
        {
            int a;
 
            ss >> a;
            if(ss.fail())
                break;
            sum += a;
        }
        cout << sum << endl;
    }
 
    return 0;
}

使用stringstream简化类型转换

C++标准库中的<sstream>提供了比ANSI C的<stdio.h>更高级的一些功能,即单纯性、类型安全和可扩展性。接下来,我将举例说明怎样使用这些库来实现安全和自动的类型转换。
一个例子:

#include <stdio.h>
 
int main()
{
    int n = 10000;
    char s[10];
 
    sprintf(s, "%d", n);
    //s中的内容为“10000”
    //到目前为止看起来还不错。但是,对上面代码的一个微小的改变就会使程序发生错误
    printf("%s\n", s);
 
    sprintf(s, "%f", n);
    //错误的格式化符
    printf("%s\n", s);
 
    return 0;
}

在这种情况下,由于错误地使用了 %f 格式化符来替代了%d。因此,s在调用完sprintf()后包含了一个不确定的字符串。要是能自动推导出正确的类型,那不是更好吗?

进入stringstream:

由于n和s的类型在编译期就确定了,所以编译器拥有足够的信息来判断需要哪些转换。<sstream>库中声明的标准类就利用了这一点,自动选择所必需的转换。而且,转换结果保存在stringstream对象的内部缓冲中。你不必担心缓冲区溢出,因为这些对象会根据需要自动分配存储空间。

<sstream>库定义了三种类:istringstream、ostringstream和stringstream,分别用来进行流的输入、输出和输入输出操作。另外,每个类都有一个对应的宽字符集版本。简单起见,我主要以stringstream为中心,因为每个转换都要涉及到输入和输出操作。

注意,<sstream>使用string对象来代替字符数组。这样可以避免缓冲区溢出的危险。而且,传入参数和目标对象的类型被自动推导出来,即使使用了不正确的格式化符也没有危险。

  • string到int的转换
string result = "10000";  
int n = 0;  
stream << result;  
stream >> n;  //n等于10000 
  • 重复利用stringstream对象

如果你打算在多次转换中使用同一个stringstream对象,记住在每次转换前要使用clear()方法。

在多次转换中重复使用同一个stringstream(而不是每次都创建一个新的对象)对象最大的好处在于效率。stringstream对象的构造和析构函数通常是非常耗费CPU时间的。

  • 在类型转换中使用模板

你可以轻松地定义函数模板来将一个任意的类型转换到特定的目标类型。例如,需要将各种数字值,如int、long、double等等转换成字符串,要使用以一个string类型和一个任意值t为参数的to_string()函数。to_string()函数将t转换为字符串并写入result中。使用str()成员函数来获取流内部缓冲的一份拷贝。


template<class T>  
  
void to_string(string &result, const T &t)  
{  
  
    ostringstream oss;  //创建一个流  
    oss << t;  //把值传递入流中  
    result = oss.str();  //获取转换后的字符并将其写入result  
}  
 
//这样,你就可以轻松地将多种数值转换成字符串了    
to_string(s1, 10.5);  //double到string  
to_string(s2, 123);  //int到string  
to_string(s3, true);  //bool到string  
  
  
  
  
//可以更进一步定义一个通用的转换模板,用于任意类型之间的转换。函数模板convert()含有两个模板参数out_type和in_value,功能是将in_value值转换成out_type类型:  
  
template<class out_type, class in_value>  
  
out_type convert(const in_value & t)  
{  
    stringstream stream;  
  
    stream << t;  //向流中传值  
    out_type result;  //这里存储转换结果  
    stream >> result;  //向result中写入值  
  
    return result;  
}  

测试代码:


#include <iostream>
#include <string>
#include <sstream>
using namespace std;
 
template<class T>
void to_string(string &result, const T &t)
{
 
    ostringstream oss;
    oss << t;
    result = oss.str();
}
 
template<class out_type, class in_value>
out_type convert(const in_value & t)
{
    stringstream stream;
 
    stream << t;
    out_type result;
    stream >> result;
 
    return result;
}
 
int main()
{
    //to_string实例
    string s1, s2, s3;
 
    to_string(s1, 10.5);  //double到string
    to_string(s2, 123);  //int到string
    to_string(s3, true);  //bool到string
    cout << s1 << endl << s2 << endl << s3 << endl << endl;
 
    //convert()例子
    double d;
    string salary;
    string s = "12.56";
 
    d = convert <double> (s);  //d等于12.56
    salary = convert <string> (9000.0); //salary等于"9000"
 
    cout << d << endl << salary << endl;
 
    return 0;
}
  • 结论

在过去留下来的程序代码和纯粹的C程序中,传统的<stdio.h>形式的转换伴随了我们很长的一段时间。但是,如文中所述,基于stringstream的转换拥有类型安全和不会溢出这样的特性,使我们有充足得理由去使用<sstream>。<sstream>库还提供了另外一个特性—可扩展性。你可以通过重载来支持自定义类型间的转换。

  • 使用误区

如果stringstream使用不当,当心内存出问题。试试下面的代码,运行程序前打开任务管理器,看看内存变化。

复制代码,把 stream.str(""); 那一行的注释去掉,再运行程序,内存就正常了。

看来stringstream似乎不打算主动释放内存( 或许是为了提高效率 ),但如果你要在程序中用同一个流,反复读写大量的数据,将会造成大量的内存消耗,因此这时候,需要适时地清除一下缓冲 ( 用 stream.str("") )。

另外不要企图用 stream.str().resize(0) 或 stream.str().clear() 来清除缓冲,使用它们似乎可以让stringstream的内存消耗不要增长得那么快,但仍然不能达到清除stringstream缓冲的效果(做个实验就知道了,内存的消耗还在缓慢的增长)

  • clear()
    这个名字让很多人想当然地认为它会清除流的内容。
    实际上它并不清空任何内容,它只是重置了流的状态标志。
  • str("")
    清空stringstream的缓冲,每次循环内存消耗将不再增加

多行重复输入,且分别打印时,最好同时使用他们


#include <iostream>
#include <sstream>
using namespace std;
 
int main()
{
    std::stringstream stream;
    string str;
 
    while(1)
    {
        stream.clear();
        //去掉下面这行注释。
        //stream.str("");
        stream << "you see see you";
        stream >> str;
        // 去掉下面这行注释,看看每次循环,你的内存消耗会增加多少
        //cout << "Size of stream = " << stream.str().length() << endl;
    }
 
    return 0;
}

转自https://blog.csdn.net/sunshineacm/article/details/78068987

多行不定长n*n二维数组输入,并可求出n
稍加修改也可做m*n的矩阵录入

#include <iostream>
#include <vector>
#include <string>
#include <sstream>
using namespace std;

int main()
{
    string input;
    int num;
    stringstream ss;
    vector<vector<int>> a(10);
    int n=0;
    while(getline(cin,input))
    {
        ss.clear();
        ss.str("");
        ss<<input;
        cout<<ss.str()<<">end"<<endl;
        string s = ss.str();
        if(s.find(" ")==s.npos) 
        {
            cout<<s<<"succeed"<<endl;
            break;
        }
        while (ss >> num) a[n].push_back(num);
        for (int i = 0; i < a[n].size(); i++) cout << "a[" << i << "] = " << a[n][i] << " ";
        n++;
        cout << endl;
    }
    for(int i=0;i<n;i++) 
    {
        for(int j=0;j<n;j++) cout<<a[i][j]<<" ";
        cout<<endl;
    }
    
    
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容