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;
}
}
