C++字串流stringstream與string知識介紹與用法小結
之前總結了C++的檔案輸出輸入流的相關知識,通過介紹底層的streambuf緩衝區,從而與stringstream流(字串流)聯絡了起來,本文就對此進行簡單的介紹。
首先介紹string。 string 是 C++ 提供的字串類,和 C 型別的字串相比,除了有不限長度的優點外,還有其他許多方便的功能,其可以看成類似STL裡vector陣列的一種容器,可以方便的進行資料的增刪改查,並可以進行排序、交換與遍歷。要使用 string, 必須包含標頭檔案string,幷包含std名稱空間:
#include <string>
using namespace std;
宣告一個字串變數為(本質上也可以理解為class string的一個物件,包含許多的成員函式):
string str;
//可以在宣告時進行初始化
string str = "Hello";
要輸出str的單個字元,可以與傳統C的字串一樣採用下標運算str[i]的形式,也可以採用成員函式(str.at(i))的形式,不同的是[]運算不會檢查索引i是否越界,而at()函式會檢查,使用無效時會丟擲out_of_range異常。
同時,string型別的字串是不以‘\0’結尾的,因此若str有三個字元,傳統C語言的字串的str[3]是字元‘\0’,但是string型別的只能到str[2],str[3]是沒有定義的,而str. at(3)會提示越界奔潰。
C++ string型別字串與C型別的字串的簡單對比如下:
功能 | C++ string | C字元陣列 |
---|---|---|
定義字串 | string str; | char str[100]; |
單個字元輸出 | str[i] / str.at(i) | str[i] |
字串長度 | str.length() / str.size() | strlen(str) |
讀取一行 | getline(cin,str) | gets(str) |
賦值 | str = “Hello”; | strcpy(str,“Hello”); |
連線字串 | str = str + “Hello” | strcat(str,“Hello”); |
比較字串 | str == “Hello”; | strcmp(str,“Hello”); |
要使用strlen()、strcpy()函式需要包含C語言的字串操作函式標頭檔案:
#include <string.h>
using namespace std;
//上述兩行程式碼等價於下面一行程式碼
#include <cstring>
C++字串與C字串
C++ string類提供了c_str()、data()和copy()這三個成員函式用於將C++字串string轉換為C字串C_string,其
函式 | 功能 |
---|---|
c_str() | 返回一個以‘/0’結尾的字元陣列 |
data() | 以字元陣列的形式返回字串內容,但並不新增’/0’ |
copy() | 字串的內容複製或寫入既有的c_string或字元陣列內 |
string str = "Hello World!";
const char* p1 = str.c_str();
const char* p2 = str.data();
const char* p3=new char[10];
str.copy(p3,5,0);
//函式原型:copy(char *s, int n, int pos = 0)
//把當前串中以pos開始的n個字元拷貝到以s為起始位置的字元陣列中,返回實際拷貝的數目
string還可以方便的改變字串的容量大小,通過呼叫成員函式resize()可以重設string的容量。
string str="Hello";
str.resize(3);
string可以很方便的查詢字串中的字元或者子串,其是通過成員函式find()和substr()實現的, find()函式是從str第3個位置查起,找到子串後,返回子串的位置;而substr函式從pos位置(子串開始的位置)開始,擷取5個字元,賦值給str2,也就是說,str2的內容將是ssdfs。
string str = "aaaaddddssdfsasdf";
size_t pos = str.find("ssdf", 3);//注意pos的資料型別string::size_type
//如果沒找到,返回一個特殊的標誌npos
// 可以用if(pos != string::npos)則表示找到。
string str2 = str.substr(pos, 5);
二、stringstream
stringstream是 C++ 提供的一個字串流(stream),和之前學過的iostream、fstream有類似的操作方式,要使用stringstream,必須包含其標頭檔案:
#include <sstream>
using namespace std;
stringstream ss;
< sstream > 庫定義了三種類:istringstream、ostringstream和stringstream,分別用來進行流的輸入、輸出和輸入輸出操作。另外,每個類都有一個對應的寬字符集版本。一般情況下使用stringstream就足夠,因為字串要頻繁的涉及到輸入輸出。
< sstream > 使用string物件來代替字元陣列,這樣可以避免緩衝區溢位的危險。而且,傳入引數和目標物件的型別被自動推匯出來,即便使用了不正確的格式化符也沒有危險。
與檔案流fstream類似,通過插入器(<<)和析取器(>>)這兩個運算子可以直接對stringstream上的資料輸入輸出,而將stringstream中的全部資料輸出則是使用成員函式str(),其有兩種形式: 1、void str() //無參形式,用於將stringstream流中的資料以string字串的形式輸出 2、void str (const string& s)//以字串為引數,用以覆蓋stringstream流中的資料 特別需要注意的是:
// 字串流清零,將流中的資料全部清除
ss.str("");
示例程式碼:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
stringstream ss;
ss << "hello ";
ss << "world!";
std::cout << ss.str() << std::endl;
// 對stringstream而言,operator<< 是一直往字串流中寫字元
// 而不是覆蓋之前輸入的字元,這一點不同於str()成員函式方法,str()函式建立的是一個臨時的string物件
//這個string物件在函式str()語句結束就會被銷燬,因而一般使用時應先宣告一個string物件s,將str()賦值給s
//const string s=ss.str();//這樣會有一個string拷貝的過程
/*又或者是const string& s=ss.str();這樣就是用s直接引用了ss.str()這個臨時變數,就“延長了臨時變數ss.str()的
生命週期”,使得ss.str()生命結束時刻和s一樣*/
return 0;
}
ss.clear()成員函式
同文件流fstream中的clear()函式類似,通過clear()成員函式可以清除流的錯誤狀態,主要用在stringstream重複使用時或者多個stringstream物件構造時清空,不然之前的緩衝就停留在輸入輸出流中。
ss.setstate(std::ios::eofbit);//設定流的狀態標誌位
std::cout << ss.rdstate() << std::endl;//獲取當前流的狀態標誌位
// 結果為1
ss.clear();
std::cout << ss.rdstate() << std::endl;
// 結果為0
在對同一個stringstream物件重複賦值,就需要先對流使用clear()函式清空流的狀態,此時流佔用的記憶體沒有改變,會一直增加(stringstream不主動釋放記憶體),若想改變記憶體(一般是清除記憶體,減少記憶體消耗),需要再配合使用str("")清空stringstream的快取。
stringstream stream;
int a,b;
ss<<"80";//向流輸出資料(寫入)
ss>>a;//從流輸入資料到a
cout<<"Size of ss = "<<ss.str().length()<<endl;//ss.str()返回一個string物件,再呼叫其成員函式length()
ss.clear();//清空流
ss.str("");//清空流快取
cout<<"Size of ss = "<<ss.str().length()<<endl;
ss<<"90";//重新賦值
ss>>b;
cout<<"Size of ss = "<<ss.str().length()<<endl;
執行結果:
Size of ss = 2
Size of ss = 0
Size of ss = 2
80
90
stringstream與fstream
通過過載的<<和>>運算子可以將檔案流中的資料輸出到C++字串中,它們之間的媒介是緩衝區streambuf,可由流的成員函式rdbuf()讀取。
#include <iostream>
#include <sstream>//stringstream流的標頭檔案
#include <fstream>
using namespace std;
int main()
{
string str;
ifstream in;
in.open("Hello.txt");
//讀取檔案的緩衝內容到資料流中
stringstream ss;
ss << in.rdbuf();
in.close();//關閉檔案
str = ss.str();//將stringstream流中的資料賦值給string型別字串
const char* p = str.c_str();//將字串內容轉化為C_string型別
return 0;
}
stringstream通常是用來做資料轉換的,用於字串與其他變數型別的轉換,相比c庫的轉換,它更加安全,自動和直接。
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
string str1("How are you? 123 1 4.368");
stringstream ss(str1);//建構函式初始化
cout<<ss.str1()<<endl;
string str2;
for(int i=0;i<3;i++)
{
ss>>str2;
cout<<str2<<" ";
}
int a;
ss>>a;
cout<<a<<endl;
bool b;
ss>>b;
cout<<b<<endl;
float c;
ss>>c;
cout<<c<<endl;
ss.clear();
ss.str1("I am fine!");//重新賦值
while(ss>>str2)//不斷讀取
{
cout<<str2<<" ";
}
}
執行結果:
How are you? 123 1 4.368
How are you?
123
1
4.368
由上面的程式碼可知,從stringstream流中的資料輸入字串到一個變數裡,是以遇到空格跳到下一個字串的這樣的形式連續讀取的。