stringstream

stringstream是 C++ 提供的另一個(gè)字串型的串流(stream)物件,和之前學(xué)過的iostream、fstream有類似的操作方式。要使用stringstream, 必須先加入這一行:

include <sstream>

tringstream主要是用在將一個(gè)字符串分割,可以先用.clear( )以及.str( )將指定字串設(shè)定成一開始的內(nèi)容,再用>>把個(gè)別的資料輸出。

舉個(gè)例子:
題目:輸入的第一行有一個(gè)數(shù)字 N 代表接下來有 N 行資料,每一行資料里有不固定個(gè)數(shù)的整數(shù)(最多20個(gè),每行最大200個(gè)字元),編程將每行的總和打印出來。

輸入:
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簡化類型轉(zhuǎn)換

C++標(biāo)準(zhǔn)庫中的<sstream>提供了比ANSI C的<stdio.h>更高級的一些功能,即單純性、類型安全和可擴(kuò)展性。接下來,我將舉例說明怎樣使用這些庫來實(shí)現(xiàn)安全和自動的類型轉(zhuǎn)換。
一個(gè)例子:

#include <stdio.h>
 
int main()
{
    int n = 10000;
    char s[10];
 
    sprintf(s, "%d", n);
    //s中的內(nèi)容為“10000”
    //到目前為止看起來還不錯。但是,對上面代碼的一個(gè)微小的改變就會使程序發(fā)生錯誤
    printf("%s\n", s);
 
    sprintf(s, "%f", n);
    //錯誤的格式化符
    printf("%s\n", s);
 
    return 0;
}

在這種情況下,由于錯誤地使用了 %f 格式化符來替代了%d。因此,s在調(diào)用完sprintf()后包含了一個(gè)不確定的字符串。要是能自動推導(dǎo)出正確的類型,那不是更好嗎?

進(jìn)入stringstream:

由于n和s的類型在編譯期就確定了,所以編譯器擁有足夠的信息來判斷需要哪些轉(zhuǎn)換。<sstream>庫中聲明的標(biāo)準(zhǔn)類就利用了這一點(diǎn),自動選擇所必需的轉(zhuǎn)換。而且,轉(zhuǎn)換結(jié)果保存在stringstream對象的內(nèi)部緩沖中。你不必?fù)?dān)心緩沖區(qū)溢出,因?yàn)檫@些對象會根據(jù)需要自動分配存儲空間。

<sstream>庫定義了三種類:istringstream、ostringstream和stringstream,分別用來進(jìn)行流的輸入、輸出和輸入輸出操作。另外,每個(gè)類都有一個(gè)對應(yīng)的寬字符集版本。簡單起見,我主要以stringstream為中心,因?yàn)槊總€(gè)轉(zhuǎn)換都要涉及到輸入和輸出操作。

注意,<sstream>使用string對象來代替字符數(shù)組。這樣可以避免緩沖區(qū)溢出的危險(xiǎn)。而且,傳入?yún)?shù)和目標(biāo)對象的類型被自動推導(dǎo)出來,即使使用了不正確的格式化符也沒有危險(xiǎn)。

  • string到int的轉(zhuǎn)換
string result = "10000";  
int n = 0;  
stream << result;  
stream >> n;  //n等于10000 
  • 重復(fù)利用stringstream對象

如果你打算在多次轉(zhuǎn)換中使用同一個(gè)stringstream對象,記住在每次轉(zhuǎn)換前要使用clear()方法。

在多次轉(zhuǎn)換中重復(fù)使用同一個(gè)stringstream(而不是每次都創(chuàng)建一個(gè)新的對象)對象最大的好處在于效率。stringstream對象的構(gòu)造和析構(gòu)函數(shù)通常是非常耗費(fèi)CPU時(shí)間的。

  • 在類型轉(zhuǎn)換中使用模板

你可以輕松地定義函數(shù)模板來將一個(gè)任意的類型轉(zhuǎn)換到特定的目標(biāo)類型。例如,需要將各種數(shù)字值,如int、long、double等等轉(zhuǎn)換成字符串,要使用以一個(gè)string類型和一個(gè)任意值t為參數(shù)的to_string()函數(shù)。to_string()函數(shù)將t轉(zhuǎn)換為字符串并寫入result中。使用str()成員函數(shù)來獲取流內(nèi)部緩沖的一份拷貝。


template<class T>  
  
void to_string(string &result, const T &t)  
{  
  
    ostringstream oss;  //創(chuàng)建一個(gè)流  
    oss << t;  //把值傳遞入流中  
    result = oss.str();  //獲取轉(zhuǎn)換后的字符并將其寫入result  
}  
 
//這樣,你就可以輕松地將多種數(shù)值轉(zhuǎn)換成字符串了    
to_string(s1, 10.5);  //double到string  
to_string(s2, 123);  //int到string  
to_string(s3, true);  //bool到string  
  
  
  
  
//可以更進(jìn)一步定義一個(gè)通用的轉(zhuǎn)換模板,用于任意類型之間的轉(zhuǎn)換。函數(shù)模板convert()含有兩個(gè)模板參數(shù)out_type和in_value,功能是將in_value值轉(zhuǎn)換成out_type類型:  
  
template<class out_type, class in_value>  
  
out_type convert(const in_value & t)  
{  
    stringstream stream;  
  
    stream << t;  //向流中傳值  
    out_type result;  //這里存儲轉(zhuǎn)換結(jié)果  
    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實(shí)例
    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;
}
  • 結(jié)論

在過去留下來的程序代碼和純粹的C程序中,傳統(tǒng)的<stdio.h>形式的轉(zhuǎn)換伴隨了我們很長的一段時(shí)間。但是,如文中所述,基于stringstream的轉(zhuǎn)換擁有類型安全和不會溢出這樣的特性,使我們有充足得理由去使用<sstream>。<sstream>庫還提供了另外一個(gè)特性—可擴(kuò)展性。你可以通過重載來支持自定義類型間的轉(zhuǎn)換。

  • 使用誤區(qū)

如果stringstream使用不當(dāng),當(dāng)心內(nèi)存出問題。試試下面的代碼,運(yùn)行程序前打開任務(wù)管理器,看看內(nèi)存變化。

復(fù)制代碼,把 stream.str(""); 那一行的注釋去掉,再運(yùn)行程序,內(nèi)存就正常了。

看來stringstream似乎不打算主動釋放內(nèi)存( 或許是為了提高效率 ),但如果你要在程序中用同一個(gè)流,反復(fù)讀寫大量的數(shù)據(jù),將會造成大量的內(nèi)存消耗,因此這時(shí)候,需要適時(shí)地清除一下緩沖 ( 用 stream.str("") )。

另外不要企圖用 stream.str().resize(0) 或 stream.str().clear() 來清除緩沖,使用它們似乎可以讓stringstream的內(nèi)存消耗不要增長得那么快,但仍然不能達(dá)到清除stringstream緩沖的效果(做個(gè)實(shí)驗(yàn)就知道了,內(nèi)存的消耗還在緩慢的增長)

  • clear()
    這個(gè)名字讓很多人想當(dāng)然地認(rèn)為它會清除流的內(nèi)容。
    實(shí)際上它并不清空任何內(nèi)容,它只是重置了流的狀態(tài)標(biāo)志。
  • str("")
    清空stringstream的緩沖,每次循環(huán)內(nèi)存消耗將不再增加

多行重復(fù)輸入,且分別打印時(shí),最好同時(shí)使用他們


#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;
        // 去掉下面這行注釋,看看每次循環(huán),你的內(nèi)存消耗會增加多少
        //cout << "Size of stream = " << stream.str().length() << endl;
    }
 
    return 0;
}

轉(zhuǎn)自https://blog.csdn.net/sunshineacm/article/details/78068987

多行不定長n*n二維數(shù)組輸入,并可求出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;
    }
    
    
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容