string類
聲明
string類本不是STL的容器,但是它與STL容器有着很多相似的操作,因此,把string放在這裏一起進行介紹。
之所以拋棄char*的字符串而選用C++標準程序庫中的string類,是因爲他和前者比較起來,不必擔心內存是否足夠、字符串長度等等,而且作爲一個類出現,他集成的操作函數足以完成我們大多數情況下的需要。我們儘可以把它看成是C++的基本數據類型。
首先,爲了在我們的程序中使用string類型,我們必須包含頭文件。如下:
#include <string> // 注意這裏不是string.h,string.h是C字符串頭文件
1、聲明一個C++字符串
聲明一個字符串變量很簡單: string str;
這樣我們就聲明瞭一個字符串變量,但既然是一個類,就有構造函數和析構函數。上面的聲明沒有傳入參數,所以就直接使用了string的默認的構造函數,這個函數所作的就是把str初始化爲一個空字符串。string類的構造函數和析構函數如下:
1) string s; // 生成一個空字符串s
2) string s(str) ; // 拷貝構造函數生成str的複製品
3) string s(str, stridx); // 將字符串str內"始於位置stridx"的部分當作字符串的初值
4) string s(str, stridx, strlen) ; // 將字符串str內"始於stridx且長度頂多strlen"的部分作爲字符串的初值
5) string s(cstr) ; // 將C字符串(以NULL結束)作爲s的初值
6) string s(chars, chars_len) ; // 將C字符串前chars_len個字符作爲字符串s的初值。
7) string s(num, ‘c’) ; // 生成一個字符串,包含num個c字符
8) string s(“value”); string s=“value”; // 將s初始化爲一個字符串字面值副本
9) string s(begin, end); // 以區間begin/end(不包含end)內的字符作爲字符串s的初值
10) s.~string(); //銷燬所有字符,釋放內存
2、string與C字符數組的比較
string串要取得其中某一個字符,和傳統的C字符串一樣,可以用s[i]的方式取得。比較不一樣的是如果s有三個字符,傳統C的字符串的s[3]是’\0’字符,但是C++的string則是隻到s[2]這個字符而已。
1、C風格字符串
- 用”“括起來的字符串常量,C++中的字符串常量由編譯器在末尾添加一個空字符;
- 末尾添加了‘\0’的字符數組,C風格字符串的末尾必須有一個’\0’。
2、C字符數組及其與string串的區別
- char ch[ ]={‘C’, ‘+’, ‘+’}; //末尾無NULL
- char ch[ ]={‘C’, ‘+’, ‘+’, ‘\0’}; //末尾顯式添加NULL
- char ch[ ]=”C++”; //末尾自動添加NULL字符 若[ ]內數字大於實際字符數,將實際字符存入數組,其餘位置全部爲’\0’。
3、string對象的操作
string s;
1) s.empty(); // s爲空串 返回true
2) s.size(); // 返回s中字符個數 類型應爲:string::size_type
3) s[n]; // 從0開始相當於下標訪問
4) s1+s2; // 把s1和s2連接成新串 返回新串
5) s1=s2; // 把s1替換爲s2的副本
6) v1==v2; // 比較,相等返回true
7) `!=, <, <=, >, >=` 慣有操作 任何一個大寫字母都小於任意的小寫字母
當進行string對象和字符串字面值混合連接操作時,+操作符的左右操作數必須至少有一個是string類型的:
string s1(“hello”);
string s3=s1+”world”; //合法操作
string s4=”hello”+”world”; //非法操作:兩個字符串字面值相加
4、字符串操作函數
1、string類函數
1) =, s.assign() // 賦以新值
2) swap() // 交換兩個字符串的內容
3) +=, s.append(), s.push_back() // 在尾部添加字符
4) s.insert() // 插入字符
5) s.erase() // 刪除字符
6) s.clear() // 刪除全部字符
7) s.replace() // 替換字符
8) + // 串聯字符串
9) ==,!=,<,<=,>,>=,compare() // 比較字符串
10) size(),length() // 返回字符數量
11) max_size() // 返回字符的可能最大個數
12) s.empty() // 判斷字符串是否爲空
13) s.capacity() // 返回重新分配之前的字符容量
14) reserve() // 保留一定量內存以容納一定數量的字符
15) [ ], at() // 存取單一字符
16) >>,getline() // 從stream讀取某值
17) << // 將謀值寫入stream
18) copy() // 將某值賦值爲一個C_string
19) c_str() // 返回一個指向正規C字符串(C_string)的指針 內容與本string串相同 有’\0’
20) data() // 將內容以字符數組形式返回 無’\0’
21) s.substr() // 返回某個子字符串
22) begin() end() // 提供類似STL的迭代器支持
23) rbegin() rend() // 逆向迭代器
24) get_allocator() // 返回配置器
2、函數說明
1、s.assign();
s.assign(str); // 不說
s.assign(str,1,3); // 如果str是"iamangel" 就是把"ama"賦給字符串
s.assign(str,2,string::npos); // 把字符串str從索引值2開始到結尾賦給s
s.assign("gaint"); // 不說
s.assign("nico",5); // 把’n’ ‘I’ ‘c’ ‘o’ ‘\0’賦給字符串
s.assign(5,'x'); // 把五個x賦給字符串
2、大小和容量函數
一個C++字符串存在三種大小:
1) 現有的字符數,函數是s.size()和s.length(),他們等效。s.empty()用來檢查字符串是否爲空。
2) max_size(); 這個大小是指當前C++字符串最多能包含的字符數,很可能和機器本身的限制或者字符串所在位置連續內存的大小有關係。
3) capacity()重新分配內存之前string所能包含的最大字符數。
這裏另一個需要指出的是reserve()函數,這個函數爲string重新分配內存。重新分配的大小由其參數決定,默認參數爲0,這時候會對string進行非強制性縮減。
3、元素存取
我們可以使用下標操作符[]和函數at()對元素包含的字符進行訪問。但是應該注意的是操作符[]並不檢查索引是否有效(有效索引0~str.length()),如果索引失效,會引起未定義的行爲。而at()會檢查,如果使用at()的時候索引無效,會拋出out_of_range異常。
有一個例外不得不說,const string a;的操作符[]對索引值是a.length()仍然有效,其返回值是’\0’。其他的各種情況,a.length()索引都是無效的。
4、比較函數
C ++字符串支持常見的比較操作符(>,>=,<,<=,==,!=),甚至支持string與C-string的比較(如 str<”hello”)。在使用>,>=,<,<=這些操作符的時候是根據”當前字符特性”將字符按字典順序進行逐一的比較。字典排序靠前的字符小,比較的順序是從前向後比較,遇到不相等的字符就按這個位置上的兩個字符的比較結果確定兩個字符串的大小。
另一個功能強大的比較函數是成員函數compare()。他支持多參數處理,支持用索引值和長度定位子串來進行比較。他返回一個整數來表示比較結果,返回值意義如下:0-相等 、>0-大於、<0-小於。
5、插入字符
也許你需要在string中間的某個位置插入字符串,這時候你可以用insert()函數,這個函數需要你指定一個安插位置的索引,被插入的字符串將放在這個索引的後面。
s.insert(0,”my name”);
s.insert(1,str);
這種形式的insert()函數不支持傳入單個字符,這時的單個字符必須寫成字符串形式。爲了插入單個字符,insert()函數提供了兩個對插入單個字符操作的重載函數:
insert(size_type index, size_type num, chart c)和insert(iterator pos, size_type num, chart c)。
其中size_type是無符號整數,iterator是char*,所以,你這麼調用insert函數是不行的:
insert(0, 1, ‘j’);這時候第一個參數將轉換成哪一個呢?
所以你必須這麼寫:insert((string::size_type)0, 1, ‘j’)!
第二種形式指出了使用迭代器安插字符的形式。
6、提取子串s.substr()
s.substr(); // 返回s的全部內容
s.substr(11); // 從索引11往後的子串
s.substr(5,6); // 從索引5開始6個字符
5、字符串流stringstream操作
Iostream標準庫支持內存中的輸入輸出,只要將流與存儲在程序內存中的string對象捆綁起來即可。此時,可使用iostream輸入和輸出操作符讀寫這個stream對象。使用stringstream,我們必須包含頭文件#include。
1、string s
1) >>操作符 // 用於從istream對象中讀入輸入
2) is >> s; // 從輸入流is中讀取一個以空白字符分割的字符串,寫入s
3) <<操作符 // 用於把輸出寫到ostream對象中
4) os << s; // 將s寫到輸出流os中
5) getline(is, s); // 從輸入流is中讀取一行字符,寫入s,直到遇到分行符或到了文件尾
6) istream // 輸入流 提供輸入操作
7) ostream // 輸出流 提供輸出操作
2、stringstream特定的操作
1) stringstream strm; // 創建自由的stringstream對象
2) stringstream strm(s); // 創建存儲s的副本的stringstream對象,s是stringstream類型
3) strm.str(); // 返回strm中存儲的string類型對象
4) strm.str(s); // 將string類型的s複製給strm 返回void
3、string到int的轉換
stringstream通常是用來做數據轉換的,如果你打算在多次轉換中使用同一個stringstream對象,記住在每次轉換前要使用clear()方法。在多次轉換中重複使用同一個stringstream(而不是每次都創建一個新的對象)對象最大的好處在於效率。stringstream對象的構造和析構函數通常是非常耗費CPU時間的。
string到int的轉換(與其他類型間的轉換一樣大同小異):
string result=”10000”;
int n=0;
stream<<result;
stream>>n; // n等於10000
6、C字符串、string串、stringstream之間的關係
首先必須瞭解,string可以被看成是以字符爲元素的一種容器。字符構成序列(字符串)。有時候在字符序列中進行遍歷,標準的string類提供了STL容器接口。具有一些成員函數比如begin()、end(),迭代器可以根據他們進行定位。注意,與char*不同的是,string不一定以NULL(‘\0’)結束。string長度可以根據length()得到,string可以根據下標訪問。所以,不能將string直接賦值給char*。
1、string轉換成const char *
如果要將字面值string直接轉換成const char *類型。string有2個函數可以運用:一個是.c_str(),一個是data成員函數。
c_str()函數返回一個指向正規C字符串的指針,內容與本string串相同。這是爲了與C語言兼容,在C語言中沒有string類型,故必須通過string類對象的成員函數c_str()把string 對象轉換成C中的字符串樣式。注意:一定要使用strcpy()函數等來操作方法c_str()返回的指針
string str = "Hello World";
const char *ch1 = str.c_str();
const char *ch2 = str.data();
此時,ch1與ch2的內容將都是”Hello World”。但是隻能轉換成const char*,如果去掉const編譯不能通過。
2、string轉換成char *
C++提供的由C++字符串得到對應的C_string的方法是使用data()、c_str()和copy(),其中
1) data()以字符數組的形式返回字符串內容,但並不添加’\0’。
2) c_str()返回一個以’\0’結尾的字符數組,返回值是const char*。
3) copy()則把字符串的內容複製或寫入既有的c_string或字符數組內。
C++字符串並不以’\0’結尾。我的建議是在程序中能使用C++字符串就使用,除非萬不得已不選用c_string。
如果要轉換成char*,可以用string的一個成員函數strcpy實現。
string str = "Hello World";
int len = str.length();
char *data = new char[len+1]; //這裏+1還是不+1需要注意
strcpy(data, str.c_str()); // const char *data = new char[len+1]; strcpy(data, str);
此時,data中的內容爲”Hello World”使用c_str()要麼str賦給一個const指針,要麼用strcpy()複製。
3、char *轉換成string
string類型能夠自動將C風格的字符串轉換成string對象:
string str;
const char *pc = "Hello World";
str = pc;
printf(“%s\n”, str); //此處出現錯誤的輸出
cout<<str<<endl;
不過這個是會出現問題的。有一種情況我要說明一下。當我們定義了一個string類型之後,用printf(“%s”,str);輸出是會出問題的。這是因爲“%s”要求後面的對象的首地址。但是string不是這樣的一個類型。所以肯定出錯。
用cout輸出是沒有問題的,若一定要printf輸出。那麼可以這樣:
printf("%s",str.c_str());
4、char[ ] 轉換成string
這個與char*的情況相同,也可以直接賦值,但是也會出現上面的問題,需要同樣的處理。
- 字符數組轉化成string類型:
char ch [] = "ABCDEFG";
string str(ch); //也可string str = ch;
或者
char ch [] = "ABCDEFG";
string str;
str = ch; //在原有基礎上添加可以用str += ch;
5、string轉換成char[ ]
string對象轉換成C風格的字符串:
const char *str = s.c_str();
這是因爲爲了防止字符數組被程序直接處理c_str()返回了一個指向常量數組的指針。
由於我們知道string的長度可以根據length()函數得到,又可以根據下標直接訪問,所以用一個循環就可以賦值了,這樣的轉換不可以直接賦值。
string str = "Hello World";
int len=str.length();
char ch[255]={};
for( int i=0;i<str.length();i++)
ch[i] = str[i];
ch[len+1] = '\0';
printf("%s\n", ch);
cout<<ch<<endl;
6、stringstream與string間的綁定
stringstream strm;
string s;
strm<<s; // 將s寫入到strm
strm>>s; // 從strm讀取串寫入s
strm.str(); // 返回strm中存儲的string類型對象
strm.str(s); // 將string類型的s複製給strm 返回void
char* cstr; // 將C字符數組轉換成流
string str(cstr);
stringstream ss(str);