STL中map和string, vector 用法详解
1. map 用法詳解
std map是STL的一個(gè)關(guān)聯(lián)容器,它提供一對(duì)一(其中第一個(gè)可以稱(chēng)為關(guān)鍵字,每個(gè)關(guān)鍵字只能在map中出現(xiàn)一次,第二個(gè)可能稱(chēng)為該關(guān)鍵字的值)的數(shù)據(jù)處理能力,由于這個(gè)特性,它完成有可能在我們處理一對(duì)一數(shù)據(jù)的時(shí)候,在編程上提供快速通道。這里說(shuō)下std map內(nèi)部數(shù)據(jù)的組織,std map內(nèi)部自建一顆紅黑樹(shù)(一種非嚴(yán)格意義上的平衡二叉樹(shù)),這顆樹(shù)具有對(duì)數(shù)據(jù)自動(dòng)排序的功能,所以在std map內(nèi)部所有的數(shù)據(jù)都是有序的,后邊我們會(huì)見(jiàn)識(shí)到有序的好處。
下面舉例說(shuō)明什么是一對(duì)一的數(shù)據(jù)映射。比如一個(gè)班級(jí)中,每個(gè)學(xué)生的學(xué)號(hào)跟他的姓名就存在著一一映射的關(guān)系,這個(gè)模型用map可能輕易描述,很明顯學(xué)號(hào)用int描述,姓名用字符串描述(本篇文章中不用char *來(lái)描述字符串,而是采用STL中string來(lái)描述),下面給出map描述代碼:
Map<int, string> mapStudent;
1. map的構(gòu)造函數(shù)
map共提供了6個(gè)構(gòu)造函數(shù),這塊涉及到內(nèi)存分配器這些東西,略過(guò)不表,在下面我們將接觸到一些map的構(gòu)造方法,這里要說(shuō)下的就是,我們通常用如下方法構(gòu)造一個(gè)map:
Map<int, string> mapStudent;
2. 數(shù)據(jù)的插入
在構(gòu)造map容器后,我們就可以往里面插入數(shù)據(jù)了。這里講三種插入數(shù)據(jù)的方法:
第一種:用insert函數(shù)插入pair數(shù)據(jù),下面舉例說(shuō)明(以下代碼雖然是隨手寫(xiě)的,應(yīng)該可以在VC和GCC下編譯通過(guò),大家可以運(yùn)行下看什么效果,在VC下請(qǐng)加入這條語(yǔ)句,屏蔽4786警告 #pragma warning (disable:4786) )
#include <map>
#include <string>
#include <iostream>
Using namespace std;
Int main()
{
Map<int, string> mapStudent;
mapStudent.insert(pair<int, string>(1, “student_one”));
mapStudent.insert(pair<int, string>(2, “student_two”));
mapStudent.insert(pair<int, string>(3, “student_three”));
map<int, string>::iterator iter;
for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)
{
Cout<<iter->first<<” ”<<iter->second<<end;
}
}
第二種:用insert函數(shù)插入value_type數(shù)據(jù),下面舉例說(shuō)明
#include <map>
#include <string>
#include <iostream>
Using namespace std;
Int main()
{
Map<int, string> mapStudent;
mapStudent.insert(map<int, string>::value_type (1, “student_one”));
mapStudent.insert(map<int, string>::value_type (2, “student_two”));
mapStudent.insert(map<int, string>::value_type (3, “student_three”));
map<int, string>::iterator iter;
for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)
{
Cout<<iter->first<<” ”<<iter->second<<end;
}
}
第三種:用數(shù)組方式插入數(shù)據(jù),下面舉例說(shuō)明
#include <map>
#include <string>
#include <iostream>
Using namespace std;
Int main()
{
Map<int, string> mapStudent;
mapStudent[1] = “student_one”;
mapStudent[2] = “student_two”;
mapStudent[3] = “student_three”;
map<int, string>::iterator iter;
for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)
{
Cout<<iter->first<<” ”<<iter->second<<end;
}
}
以上三種用法,雖然都可以實(shí)現(xiàn)數(shù)據(jù)的插入,但是它們是有區(qū)別的,當(dāng)然了第一種和第二種在效果上是完成一樣的,用insert函數(shù)插入數(shù)據(jù),在數(shù)據(jù)的插入上涉及到集合的唯一性這個(gè)概念,即當(dāng)map中有這個(gè)關(guān)鍵字時(shí),insert操作是插入數(shù)據(jù)不了的,但是用數(shù)組方式就不同了,它可以覆蓋以前該關(guān)鍵字對(duì)應(yīng)的值,用程序說(shuō)明
mapStudent.insert(map<int, string>::value_type (1, “student_one”));
mapStudent.insert(map<int, string>::value_type (1, “student_two”));
上面這兩條語(yǔ)句執(zhí)行后,map中1這個(gè)關(guān)鍵字對(duì)應(yīng)的值是“student_one”,第二條語(yǔ)句并沒(méi)有生效,那么這就涉及到我們?cè)趺粗纈nsert語(yǔ)句是否插入成功的問(wèn)題了,可以用pair來(lái)獲得是否插入成功,程序如下
Pair<map<int, string>::iterator, bool> Insert_Pair;
Insert_Pair = mapStudent.insert(map<int, string>::value_type (1, “student_one”));
我們通過(guò)pair的第二個(gè)變量來(lái)知道是否插入成功,它的第一個(gè)變量返回的是一個(gè)map的迭代器,如果插入成功的話Insert_Pair.second應(yīng)該是true的,否則為false。
下面給出完成代碼,演示插入成功與否問(wèn)題
#include <map>
#include <string>
#include <iostream>
Using namespace std;
Int main()
{
Map<int, string> mapStudent;
Pair<map<int, string>::iterator, bool> Insert_Pair;
Insert_Pair = mapStudent.insert(pair<int, string>(1, “student_one”));
If(Insert_Pair.second == true)
{
Cout<<”Insert Successfully”<<endl;
}
Else
{
Cout<<”Insert Failure”<<endl;
}
Insert_Pair = mapStudent.insert(pair<int, string>(1, “student_two”));
If(Insert_Pair.second == true)
{
Cout<<”Insert Successfully”<<endl;
}
Else
{
Cout<<”Insert Failure”<<endl;
}
map<int, string>::iterator iter;
for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)
{
Cout<<iter->first<<” ”<<iter->second<<end;
}
}
大家可以用如下程序,看下用數(shù)組插入在數(shù)據(jù)覆蓋上的效果
#include <map>
#include <string>
#include <iostream>
Using namespace std;
Int main()
{
Map<int, string> mapStudent;
mapStudent[1] = “student_one”;
mapStudent[1] = “student_two”;
mapStudent[2] = “student_three”;
map<int, string>::iterator iter;
for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)
{
Cout<<iter->first<<” ”<<iter->second<<end;
}
}
3. map的大小
在往map里面插入了數(shù)據(jù),我們?cè)趺粗喇?dāng)前已經(jīng)插入了多少數(shù)據(jù)呢,可以用size函數(shù),用法如下:
Int nSize = mapStudent.size();
4. 數(shù)據(jù)的遍歷
這里也提供三種方法,對(duì)map進(jìn)行遍歷
第一種:應(yīng)用前向迭代器,上面舉例程序中到處都是了,略過(guò)不表
第二種:應(yīng)用反相迭代器,下面舉例說(shuō)明,要體會(huì)效果,請(qǐng)自個(gè)動(dòng)手運(yùn)行程序
#include <map>
#include <string>
#include <iostream>
Using namespace std;
Int main()
{
Map<int, string> mapStudent;
mapStudent.insert(pair<int, string>(1, “student_one”));
mapStudent.insert(pair<int, string>(2, “student_two”));
mapStudent.insert(pair<int, string>(3, “student_three”));
map<int, string>::reverse_iterator iter;
for(iter = mapStudent.rbegin(); iter != mapStudent.rend(); iter++)
{
Cout<<iter->first<<” ”<<iter->second<<end;
}
}
第三種:用數(shù)組方式,程序說(shuō)明如下
#include <map>
#include <string>
#include <iostream>
Using namespace std;
Int main()
{
Map<int, string> mapStudent;
mapStudent.insert(pair<int, string>(1, “student_one”));
mapStudent.insert(pair<int, string>(2, “student_two”));
mapStudent.insert(pair<int, string>(3, “student_three”));
int nSize = mapStudent.size()
//此處有誤,應(yīng)該是 for(int nIndex = 1; nIndex <= nSize; nIndex++)
//by rainfish
for(int nIndex = 0; nIndex < nSize; nIndex++)
{
Cout<<mapStudent[nIndex]<<end;
}
}
5. 數(shù)據(jù)的查找(包括判定這個(gè)關(guān)鍵字是否在map中出現(xiàn))
在這里我們將體會(huì),map在數(shù)據(jù)插入時(shí)保證有序的好處。
要判定一個(gè)數(shù)據(jù)(關(guān)鍵字)是否在map中出現(xiàn)的方法比較多,這里標(biāo)題雖然是數(shù)據(jù)的查找,在這里將穿插著大量的map基本用法。
這里給出三種數(shù)據(jù)查找方法
第一種:用count函數(shù)來(lái)判定關(guān)鍵字是否出現(xiàn),其缺點(diǎn)是無(wú)法定位數(shù)據(jù)出現(xiàn)位置,由于map的特性,一對(duì)一的映射關(guān)系,就決定了count函數(shù)的返回值只有兩個(gè),要么是0,要么是1,出現(xiàn)的情況,當(dāng)然是返回1了
第二種:用find函數(shù)來(lái)定位數(shù)據(jù)出現(xiàn)位置,它返回的一個(gè)迭代器,當(dāng)數(shù)據(jù)出現(xiàn)時(shí),它返回?cái)?shù)據(jù)所在位置的迭代器,如果map中沒(méi)有要查找的數(shù)據(jù),它返回的迭代器等于end函數(shù)返回的迭代器,程序說(shuō)明
#include <map>
#include <string>
#include <iostream>
Using namespace std;
Int main()
{
Map<int, string> mapStudent;
mapStudent.insert(pair<int, string>(1, “student_one”));
mapStudent.insert(pair<int, string>(2, “student_two”));
mapStudent.insert(pair<int, string>(3, “student_three”));
map<int, string>::iterator iter;
iter = mapStudent.find(1);
if(iter != mapStudent.end())
{
Cout<<”Find, the value is ”<<iter->second<<endl;
}
Else
{
Cout<<”Do not Find”<<endl;
}
}
第三種:這個(gè)方法用來(lái)判定數(shù)據(jù)是否出現(xiàn),是顯得笨了點(diǎn),但是,我打算在這里講解
Lower_bound函數(shù)用法,這個(gè)函數(shù)用來(lái)返回要查找關(guān)鍵字的下界(是一個(gè)迭代器)
Upper_bound函數(shù)用法,這個(gè)函數(shù)用來(lái)返回要查找關(guān)鍵字的上界(是一個(gè)迭代器)
例如:map中已經(jīng)插入了1,2,3,4的話,如果lower_bound(2)的話,返回的2,而upper-bound(2)的話,返回的就是3
Equal_range函數(shù)返回一個(gè)pair,pair里面第一個(gè)變量是Lower_bound返回的迭代器,pair里面第二個(gè)迭代器是Upper_bound返回的迭代器,如果這兩個(gè)迭代器相等的話,則說(shuō)明map中不出現(xiàn)這個(gè)關(guān)鍵字,程序說(shuō)明
#include <map>
#include <string>
#include <iostream>
Using namespace std;
Int main()
{
Map<int, string> mapStudent;
mapStudent[1] = “student_one”;
mapStudent[3] = “student_three”;
mapStudent[5] = “student_five”;
map<int, string>::iterator iter;
iter = mapStudent.lower_bound(2);
{
//返回的是下界3的迭代器
Cout<<iter->second<<endl;
}
iter = mapStudent.lower_bound(3);
{
//返回的是下界3的迭代器
Cout<<iter->second<<endl;
}
iter = mapStudent.upper_bound(2);
{
//返回的是上界3的迭代器
Cout<<iter->second<<endl;
}
iter = mapStudent.upper_bound(3);
{
//返回的是上界5的迭代器
Cout<<iter->second<<endl;
}
Pair<map<int, string>::iterator, map<int, string>::iterator> mapPair;
mapPair = mapStudent.equal_range(2);
if(mapPair.first == mapPair.second)
{
cout<<”Do not Find”<<endl;
}
Else
{
Cout<<”Find”<<endl;
}
mapPair = mapStudent.equal_range(3);
if(mapPair.first == mapPair.second)
{
cout<<”Do not Find”<<endl;
}
Else
{
Cout<<”Find”<<endl;
}
}
6. 數(shù)據(jù)的清空與判空
清空map中的數(shù)據(jù)可以用clear()函數(shù),判定map中是否有數(shù)據(jù)可以用empty()函數(shù),它返回true則說(shuō)明是空map
7. 數(shù)據(jù)的刪除
這里要用到erase函數(shù),它有三個(gè)重載了的函數(shù),下面在例子中詳細(xì)說(shuō)明它們的用法
#include <map>
#include <string>
#include <iostream>
Using namespace std;
Int main()
{
Map<int, string> mapStudent;
mapStudent.insert(pair<int, string>(1, “student_one”));
mapStudent.insert(pair<int, string>(2, “student_two”));
mapStudent.insert(pair<int, string>(3, “student_three”));
//如果你要演示輸出效果,請(qǐng)選擇以下的一種,你看到的效果會(huì)比較好
//如果要?jiǎng)h除1,用迭代器刪除
map<int, string>::iterator iter;
iter = mapStudent.find(1);
mapStudent.erase(iter);
//如果要?jiǎng)h除1,用關(guān)鍵字刪除
Int n = mapStudent.erase(1);//如果刪除了會(huì)返回1,否則返回0
//用迭代器,成片的刪除
//一下代碼把整個(gè)map清空
mapStudent.earse(mapStudent.begin(), mapStudent.end());
//成片刪除要注意的是,也是STL的特性,刪除區(qū)間是一個(gè)前閉后開(kāi)的集合
//自個(gè)加上遍歷代碼,打印輸出吧
}
8. 其他一些函數(shù)用法
這里有swap,key_comp,value_comp,get_allocator等函數(shù),感覺(jué)到這些函數(shù)在編程用的不是很多,略過(guò)不表,有興趣的話可以自個(gè)研究
9. 排序
這里要講的是一點(diǎn)比較高深的用法了,排序問(wèn)題,STL中默認(rèn)是采用小于號(hào)來(lái)排序的,以上代碼在排序上是不存在任何問(wèn)題的,因?yàn)樯厦娴年P(guān)鍵字是int型,它本身支持小于號(hào)運(yùn)算,在一些特殊情況,比如關(guān)鍵字是一個(gè)結(jié)構(gòu)體,涉及到排序就會(huì)出現(xiàn)問(wèn)題,因?yàn)樗鼪](méi)有小于號(hào)操作,insert等函數(shù)在編譯的時(shí)候過(guò)不去,下面給出兩個(gè)方法解決這個(gè)問(wèn)題
第一種:小于號(hào)重載,程序舉例
#include <map>
#include <string>
Using namespace std;
Typedef struct tagStudentInfo
{
Int nID;
String strName;
}StudentInfo, *PStudentInfo; //學(xué)生信息
Int main()
{
int nSize;
//用學(xué)生信息映射分?jǐn)?shù)
map<StudentInfo, int>mapStudent;
map<StudentInfo, int>::iterator iter;
StudentInfo studentInfo;
studentInfo.nID = 1;
studentInfo.strName = “student_one”;
mapStudent.insert(pair<StudentInfo, int>(studentInfo, 90));
studentInfo.nID = 2;
studentInfo.strName = “student_two”;
mapStudent.insert(pair<StudentInfo, int>(studentInfo, 80));
for (iter=mapStudent.begin(); iter!=mapStudent.end(); iter++)
cout<<iter->first.nID<<endl<<iter->first.strName<<endl<<iter->second<<endl;
}
以上程序是無(wú)法編譯通過(guò)的,只要重載小于號(hào),就OK了,如下:
Typedef struct tagStudentInfo
{
Int nID;
String strName;
Bool operator < (tagStudentInfo const& _A) const
{
//這個(gè)函數(shù)指定排序策略,按nID排序,如果nID相等的話,按strName排序
If(nID < _A.nID) return true;
If(nID == _A.nID) return strName.compare(_A.strName) < 0;
Return false;
}
}StudentInfo, *PStudentInfo; //學(xué)生信息
第二種:仿函數(shù)的應(yīng)用,這個(gè)時(shí)候結(jié)構(gòu)體中沒(méi)有直接的小于號(hào)重載,程序說(shuō)明
#include <map>
#include <string>
Using namespace std;
Typedef struct tagStudentInfo
{
Int nID;
String strName;
}StudentInfo, *PStudentInfo; //學(xué)生信息
Classs sort
{
Public:
Bool operator() (StudentInfo const &_A, StudentInfo const &_B) const
{
If(_A.nID < _B.nID) return true;
If(_A.nID == _B.nID) return _A.strName.compare(_B.strName) < 0;
Return false;
}
};
Int main()
{
//用學(xué)生信息映射分?jǐn)?shù)
Map<StudentInfo, int, sort>mapStudent;
StudentInfo studentInfo;
studentInfo.nID = 1;
studentInfo.strName = “student_one”;
mapStudent.insert(pair<StudentInfo, int>(studentInfo, 90));
studentInfo.nID = 2;
studentInfo.strName = “student_two”;
mapStudent.insert(pair<StudentInfo, int>(studentInfo, 80));
}
10. 另外
由于STL是一個(gè)統(tǒng)一的整體,map的很多用法都和STL中其它的東西結(jié)合在一起,比如在排序上,這里默認(rèn)用的是小于號(hào),即less<>,如果要從大到小排序呢,這里涉及到的東西很多,在此無(wú)法一一加以說(shuō)明。
還要說(shuō)明的是,map中由于它內(nèi)部有序,由紅黑樹(shù)保證,因此很多函數(shù)執(zhí)行的時(shí)間復(fù)雜度都是log2N的,如果用map函數(shù)可以實(shí)現(xiàn)的功能,而STL Algorithm也可以完成該功能,建議用map自帶函數(shù),效率高一些。
下面說(shuō)下,map在空間上的特性,否則,估計(jì)你用起來(lái)會(huì)有時(shí)候表現(xiàn)的比較郁悶,由于map的每個(gè)數(shù)據(jù)對(duì)應(yīng)紅黑樹(shù)上的一個(gè)節(jié)點(diǎn),這個(gè)節(jié)點(diǎn)在不保存你的數(shù)據(jù)時(shí),是占用16個(gè)字節(jié)的,一個(gè)父節(jié)點(diǎn)指針,左右孩子指針,還有一個(gè)枚舉值(標(biāo)示紅黑的,相當(dāng)于平衡二叉樹(shù)中的平衡因子),我想大家應(yīng)該知道,這些地方很費(fèi)內(nèi)存了吧,不說(shuō)了……
2. string 用法詳解
C++中的string 類(lèi) 簡(jiǎn)單介紹
?前言: string 的角色
1 string 使用
1.1 充分使用string 操作符
1.2 眼花繚亂的string find 函數(shù)
1.3 string insert, replace, erase 2 string 和 C風(fēng)格字符串
3 string 和 Charactor Traits
4 string 建議
5 附錄前言: string 的角色
C++ 語(yǔ)言是個(gè)十分優(yōu)秀的語(yǔ)言,但優(yōu)秀并不表示完美。還是有許多人不愿意使用C或者C++,為什么?原因眾多,其中之一就是C/C++的文本處理功能太麻煩,用起來(lái)很不方便。以前沒(méi)有接觸過(guò)其他語(yǔ)言時(shí),每當(dāng)別人這么說(shuō),我總是不屑一顧,認(rèn)為他們根本就沒(méi)有領(lǐng)會(huì)C++的精華,或者不太懂C++,現(xiàn)在我接觸 perl, php, 和Shell腳本以后,開(kāi)始理解了以前為什么有人說(shuō)C++文本處理不方便了。
總之,有了string 后,C++的字符文本處理功能總算得到了一定補(bǔ)充,加上配合STL其他容器使用,其在文本處理上的功能已經(jīng)與perl, shell, php的距離縮小很多了。 因此掌握string 會(huì)讓你的工作事半功倍。
1、 string 使用
其實(shí),string并不是一個(gè)單獨(dú)的容器,只是basic_string 模板類(lèi)的一個(gè)typedef 而已,相對(duì)應(yīng)的還有wstring, 你在string 頭文件中你會(huì)發(fā)現(xiàn)下面的代碼:
extern "C++" {
typedef basic_string <char> string;
typedef basic_string <wchar_t> wstring;
} // extern "C++"
由于只是解釋string的用法,如果沒(méi)有特殊的說(shuō)明,本文并不區(qū)分string 和 basic_string的區(qū)別。
string 其實(shí)相當(dāng)于一個(gè)保存字符的序列容器,因此除了有字符串的一些常用操作以外,還有包含了所有的序列容器的操作。字符串的常用操作包括:增加、刪除、修改、查找比較、鏈接、輸入、輸出等。詳細(xì)函數(shù)列表參看附錄。不要害怕這么多函數(shù),其實(shí)有許多是序列容器帶有的,平時(shí)不一定用的上。
如果你要想了解所有函數(shù)的詳細(xì)用法,你需要查看basic_string,或者下載STL編程手冊(cè)。這里通過(guò)實(shí)例介紹一些常用函數(shù)。
1.1 充分使用string 操作符
string 重載了許多操作符,包括 +, +=, <, =, , [], <<, >>等,正式這些操作符,對(duì)字符串操作非常方便。先看看下面這個(gè)例子:tt.cpp(例程2)
#i nclude <string>
#i nclude <iostream>
using namespace std;
int main(){
string strinfo="Please input your name:";
cout << strinfo ;
cin >> strinfo;
if( strinfo == "winter" )
cout << "you are winter!"<<endl;
else if( strinfo != "wende" )
cout << "you are not wende!"<<endl;
else if( strinfo < "winter")
cout << "your name should be ahead of winter"<<endl;
else
cout << "your name should be after of winter"<<endl;
strinfo += " , Welcome to China!";
cout << strinfo<<endl;
cout <<"Your name is :"<<endl;
string strtmp = "How are you? " + strinfo;
for(int i = 0 ; i < strtmp.size(); i ++)
cout<<strtmp[i];
return 0;
}
下面是程序的輸出
-bash-2.05b$ make tt
c++ -O -pipe -march=pentiumpro tt.cpp -o tt
-bash-2.05b$ ./tt
Please input your name:Hero
you are not wende!
Hero , Welcome to China!
How are you? Hero , Welcome to China!
有了這些操作符,在STL中仿函數(shù)都可以直接使用string作為參數(shù),例如 less, great, equal_to 等,因此在把string作為參數(shù)傳遞的時(shí)候,它的使用和int 或者float等已經(jīng)沒(méi)有什么區(qū)別了。例如,你可以使用:
map<string, int> mymap;
//以上默認(rèn)使用了 less<string>
有了 operator + 以后,你可以直接連加,例如:
string strinfo="Winter";
string strlast="Hello " + strinfo + "!";
//你還可以這樣:
string strtest="Hello " + strinfo + " Welcome" + " to China" + " !";
看見(jiàn)其中的特點(diǎn)了嗎?只要你的等式里面有一個(gè) string 對(duì)象,你就可以一直連續(xù)"+",但有一點(diǎn)需要保證的是,在開(kāi)始的兩項(xiàng)中,必須有一項(xiàng)是 string 對(duì)象。其原理很簡(jiǎn)單:
系統(tǒng)遇到"+"號(hào),發(fā)現(xiàn)有一項(xiàng)是string 對(duì)象。
系統(tǒng)把另一項(xiàng)轉(zhuǎn)化為一個(gè)臨時(shí) string 對(duì)象。
執(zhí)行 operator + 操作,返回新的臨時(shí)string 對(duì)象。
如果又發(fā)現(xiàn)"+"號(hào),繼續(xù)第一步操作。
由于這個(gè)等式是由左到右開(kāi)始檢測(cè)執(zhí)行,如果開(kāi)始兩項(xiàng)都是const char* ,程序自己并沒(méi)有定義兩個(gè)const char* 的加法,編譯的時(shí)候肯定就有問(wèn)題了。
有了操作符以后,assign(), append(), compare(), at()等函數(shù),除非有一些特殊的需求時(shí),一般是用不上。當(dāng)然at()函數(shù)還有一個(gè)功能,那就是檢查下標(biāo)是否合法,如果是使用:
string str="winter";
//下面一行有可能會(huì)引起程序中斷錯(cuò)誤
str[100]='!';
//下面會(huì)拋出異常:throws: out_of_range
cout<<str.at(100)<<endl;
了解了嗎?如果你希望效率高,還是使用[]來(lái)訪問(wèn),如果你希望穩(wěn)定性好,最好使用at()來(lái)訪問(wèn)。
1.2 眼花繚亂的string find 函數(shù)
由于查找是使用最為頻繁的功能之一,string 提供了非常豐富的查找函數(shù)。其列表如下:
函數(shù)名 描述 find 查找 rfind 反向查找 find_first_of 查找包含子串中的任何字符,返回第一個(gè)位置 find_first_not_of 查找不包含子串中的任何字符,返回第一個(gè)位置 find_last_of 查找包含子串中的任何字符,返回最后一個(gè)位置 find_last_not_of 查找不包含子串中的任何字符,返回最后一個(gè)位置以上函數(shù)都是被重載了4次,以下是以find_first_of 函數(shù)為例說(shuō)明他們的參數(shù),其他函數(shù)和其參數(shù)一樣,也就是說(shuō)總共有24個(gè)函數(shù):
size_type find_first_of(const basic_string& s, size_type pos = 0)
size_type find_first_of(const charT* s, size_type pos, size_type n)
size_type find_first_of(const charT* s, size_type pos = 0)
size_type find_first_of(charT c, size_type pos = 0)
所有的查找函數(shù)都返回一個(gè)size_type類(lèi)型,這個(gè)返回值一般都是所找到字符串的位置,如果沒(méi)有找到,則返回string::npos。有一點(diǎn)需要特別注意,所有和string::npos的比較一定要用string::size_type來(lái)使用,不要直接使用int 或者unsigned int等類(lèi)型。其實(shí)string::npos表示的是-1, 看看頭文件:
template <class _CharT, class _Traits, class _Alloc>
const basic_string<_CharT,_Traits,_Alloc>::size_type
basic_string<_CharT,_Traits,_Alloc>::npos
= basic_string<_CharT,_Traits,_Alloc>::size_type) -1;
find 和 rfind 都還比較容易理解,一個(gè)是正向匹配,一個(gè)是逆向匹配,后面的參數(shù)pos都是用來(lái)指定起始查找位置。對(duì)于find_first_of 和find_last_of 就不是那么好理解。
find_first_of 是給定一個(gè)要查找的字符集,找到這個(gè)字符集中任何一個(gè)字符所在字符串中第一個(gè)位置?;蛟S看一個(gè)例子更容易明白。
有這樣一個(gè)需求:過(guò)濾一行開(kāi)頭和結(jié)尾的所有非英文字符。看看用string 如何實(shí)現(xiàn):
#i nclude <string>
#i nclude <iostream>
using namespace std;
int main(){
string strinfo=" //*---Hello Word!......------";
string strset="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
int first = strinfo.find_first_of(strset);
if(first == string::npos) {
cout<<"not find any characters"<<endl;
return -1;
}
int last = strinfo.find_last_of(strset);
if(last == string::npos) {
cout<<"not find any characters"<<endl;
return -1;
}
cout << strinfo.substr(first, last - first + 1)<<endl;
return 0;
}
這里把所有的英文字母大小寫(xiě)作為了需要查找的字符集,先查找第一個(gè)英文字母的位置,然后查找最后一個(gè)英文字母的位置,然后用substr 來(lái)的到中間的一部分,用于輸出結(jié)果。下面就是其結(jié)果:
Hello Word
前面的符號(hào)和后面的符號(hào)都沒(méi)有了。像這種用法可以用來(lái)查找分隔符,從而把一個(gè)連續(xù)的字符串分割成為幾部分,達(dá)到 shell 命令中的 awk 的用法。特別是當(dāng)分隔符有多個(gè)的時(shí)候,可以一次指定。例如有這樣的需求:
張三|3456123, 湖南
李四,4564234| 湖北
王小二, 4433253|北京
...
我們需要以 "|" ","為分隔符,同時(shí)又要過(guò)濾空格,把每行分成相應(yīng)的字段。可以作為你的一個(gè)家庭作業(yè)來(lái)試試,要求代碼簡(jiǎn)潔。
1.3 string insert, replace, erase
了解了string 的操作符,查找函數(shù)和substr,其實(shí)就已經(jīng)了解了string的80%的操作了。insert函數(shù), replace函數(shù)和erase函數(shù)在使用起來(lái)相對(duì)簡(jiǎn)單。下面以一個(gè)例子來(lái)說(shuō)明其應(yīng)用。
string只是提供了按照位置和區(qū)間的replace函數(shù),而不能用一個(gè)string字串來(lái)替換指定string中的另一個(gè)字串。這里寫(xiě)一個(gè)函數(shù)來(lái)實(shí)現(xiàn)這個(gè)功能:
void string_replace(string & strBig, const string & strsrc, const string &strdst) {
string::size_type pos=0;
string::size_type srclen=strsrc.size();
string::size_type dstlen=strdst.size();
while( (pos=strBig.find(strsrc, pos)) != string::npos){
strBig.replace(pos, srclen, strdst);
pos += dstlen;
}
}看看如何調(diào)用:
#i nclude <string>
#i nclude <iostream>
using namespace std;
int main() {
string strinfo="This is Winter, Winter is a programmer. Do you know Winter?";
cout<<"Orign string is :/n"<<strinfo<<endl;
string_replace(strinfo, "Winter", "wende");
cout<<"After replace Winter with wende, the string is :/n"<<strinfo<<endl;
return 0;
}其輸出結(jié)果:
Orign string is :
This is Winter, Winter is a programmer. Do you know Winter?
After replace Winter with wende, the string is :
This is wende, wende is a programmer. Do you know wende?如果不用replace函數(shù),則可以使用erase和insert來(lái)替換,也能實(shí)現(xiàn)string_replace函數(shù)的功能:
void string_replace(string & strBig, const string & strsrc, const string &strdst) {
string::size_type pos=0;
string::size_type srclen=strsrc.size();
string::size_type dstlen=strdst.size();
while( (pos=strBig.find(strsrc, pos)) != string::npos){
strBig.erase(pos, srclen);
strBig.insert(pos, strdst);
pos += dstlen;
}
}當(dāng)然,這種方法沒(méi)有使用replace來(lái)得直接。
2、 string 和 C風(fēng)格字符串
現(xiàn)在看了這么多例子,發(fā)現(xiàn)const char* 可以和string 直接轉(zhuǎn)換,例如我們?cè)谏厦娴睦又?#xff0c;使用
string_replace(strinfo, "Winter", "wende");來(lái)代用
void string_replace(string & strBig, const string & strsrc, const string &strdst) 在C語(yǔ)言中只有char* 和 const char*,為了使用起來(lái)方便,string提供了三個(gè)函數(shù)滿(mǎn)足其要求:
const charT* c_str() const
const charT* data() const
size_type copy(charT* buf, size_type n, size_type pos = 0) const 其中:
c_str 直接返回一個(gè)以/0結(jié)尾的字符串。
data 直接以數(shù)組方式返回string的內(nèi)容,其大小為size()的返回值,結(jié)尾并沒(méi)有/0字符。
copy 把string的內(nèi)容拷貝到buf空間中。
你或許會(huì)問(wèn),c_str()的功能包含data(),那還需要data()函數(shù)干什么?看看源碼:
const charT* c_str () const
{ if (length () == 0) return ""; terminate (); return data (); }原來(lái)c_str()的流程是:先調(diào)用terminate(),然后在返回data()。因此如果你對(duì)效率要求比較高,而且你的處理又不一定需要以/0的方式結(jié)束,你最好選擇data()。但是對(duì)于一般的C函數(shù)中,需要以const char*為輸入?yún)?shù),你就要使用c_str()函數(shù)。
對(duì)于c_str() data()函數(shù),返回的數(shù)組都是由string本身?yè)碛?#xff0c;千萬(wàn)不可修改其內(nèi)容。其原因是許多string實(shí)現(xiàn)的時(shí)候采用了引用機(jī)制,也就是說(shuō),有可能幾個(gè)string使用同一個(gè)字符存儲(chǔ)空間。而且你不能使用sizeof(string)來(lái)查看其大小。詳細(xì)的解釋和實(shí)現(xiàn)查看Effective STL的條款15:小心string實(shí)現(xiàn)的多樣性。
另外在你的程序中,只在需要時(shí)才使用c_str()或者data()得到字符串,每調(diào)用一次,下次再使用就會(huì)失效,如:
string strinfo("this is Winter");
...
//最好的方式是:
foo(strinfo.c_str());
//也可以這么用:
const char* pstr=strinfo.c_str();
foo(pstr);
//不要再使用了pstr了, 下面的操作已經(jīng)使pstr無(wú)效了。
strinfo += " Hello!";
foo(pstr);//錯(cuò)誤!會(huì)遇到什么錯(cuò)誤?當(dāng)你幸運(yùn)的時(shí)候pstr可能只是指向"this is Winter Hello!"的字符串,如果不幸運(yùn),就會(huì)導(dǎo)致程序出現(xiàn)其他問(wèn)題,總會(huì)有一些不可遇見(jiàn)的錯(cuò)誤??傊粫?huì)是你預(yù)期的那個(gè)結(jié)果。
3、 string 和 Charactor Traits
了解了string的用法,該詳細(xì)看看string的真相了。前面提到string 只是basic_string的一個(gè)typedef??纯碽asic_string 的參數(shù):
template <class charT, class traits = char_traits<charT>,
class Allocator = allocator<charT> >
class basic_string
{
//...
}char_traits不僅是在basic_string 中有用,在basic_istream 和 basic_ostream中也需要用到。
就像Steve Donovan在過(guò)度使用C++模板中提到的,這些確實(shí)有些過(guò)頭了,要不是系統(tǒng)自己定義了相關(guān)的一些屬性,而且用了個(gè)typedef,否則還真不知道如何使用。
但復(fù)雜總有復(fù)雜道理。有了char_traits,你可以定義自己的字符串類(lèi)型。當(dāng)然,有了char_traits < char > 和char_traits < wchar_t > 你的需求使用已經(jīng)足夠了,為了更好的理解string ,咱們來(lái)看看char_traits都有哪些要求。
如果你希望使用你自己定義的字符,你必須定義包含下列成員的結(jié)構(gòu):表達(dá)式 描述
char_type 字符類(lèi)型
int_type int 類(lèi)型
pos_type 位置類(lèi)型
off_type 表示位置之間距離的類(lèi)型
state_type 表示狀態(tài)的類(lèi)型
assign(c1,c2) 把字符c2賦值給c1
eq(c1,c2) 判斷c1,c2 是否相等
lt(c1,c2) 判斷c1是否小于c2
length(str) 判斷str的長(zhǎng)度
compare(s1,s2,n) 比較s1和s2的前n個(gè)字符
copy(s1,s2, n) 把s2的前n個(gè)字符拷貝到s1中
move(s1,s2, n) 把s2中的前n個(gè)字符移動(dòng)到s1中
assign(s,n,c) 把s中的前n個(gè)字符賦值為c
find(s,n,c) 在s的前n個(gè)字符內(nèi)查找c
eof() 返回end-of-file
to_int_type(c) 將c轉(zhuǎn)換成int_type
to_char_type(i) 將i轉(zhuǎn)換成char_type
not_eof(i) 判斷i是否為EOF
eq_int_type(i1,i2) 判斷i1和i2是否相等
想看看實(shí)際的例子,你可以看看sgi STL的char_traits結(jié)構(gòu)源碼.
現(xiàn)在默認(rèn)的string版本中,并不支持忽略大小寫(xiě)的比較函數(shù)和查找函數(shù),如果你想練練手,你可以試試改寫(xiě)一個(gè)char_traits , 然后生成一個(gè)case_string類(lèi), 也可以在string 上做繼承,然后派生一個(gè)新的類(lèi),例如:ext_string,提供一些常用的功能,例如:
1、定義分隔符。給定分隔符,把string分為幾個(gè)字段。
2、提供替換功能。例如,用winter, 替換字符串中的wende
3、大小寫(xiě)處理。例如,忽略大小寫(xiě)比較,轉(zhuǎn)換等
4、整形轉(zhuǎn)換。例如把"123"字符串轉(zhuǎn)換為123數(shù)字。
這些都是常用的功能,如果你有興趣可以試試。其實(shí)有人已經(jīng)實(shí)現(xiàn)了,看看Extended STL string。如果你想偷懶,下載一個(gè)頭文件就可以用,有了它確實(shí)方便了很多。要是有人能提供一個(gè)支持正則表達(dá)式的string,我會(huì)非常樂(lè)意用。
4、 string 建議
使用string 的方便性就不用再說(shuō)了,這里要重點(diǎn)強(qiáng)調(diào)的是string的安全性。
string并不是萬(wàn)能的,如果你在一個(gè)大工程中需要頻繁處理字符串,而且有可能是多線程,那么你一定要慎重(當(dāng)然,在多線程下你使用任何STL容器都要慎重)。
string的實(shí)現(xiàn)和效率并不一定是你想象的那樣,如果你對(duì)大量的字符串操作,而且特別關(guān)心其效率,那么你有兩個(gè)選擇,首先,你可以看看你使用的STL版本中string實(shí)現(xiàn)的源碼;另一選擇是你自己寫(xiě)一個(gè)只提供你需要的功能的類(lèi)。
string的c_str()函數(shù)是用來(lái)得到C語(yǔ)言風(fēng)格的字符串,其返回的指針不能修改其空間。而且在下一次使用時(shí)重新調(diào)用獲得新的指針。
string的data()函數(shù)返回的字符串指針不會(huì)以'/0'結(jié)束,千萬(wàn)不可忽視。
盡量去使用操作符,這樣可以讓程序更加易懂(特別是那些腳本程序員也可以看懂)
5 附錄
string 函數(shù)列表 函數(shù)名 描述
begin 得到指向字符串開(kāi)頭的Iterator
end 得到指向字符串結(jié)尾的Iterator
rbegin 得到指向反向字符串開(kāi)頭的Iterator
rend 得到指向反向字符串結(jié)尾的Iterator
size 得到字符串的大小
length 和size函數(shù)功能相同
max_size 字符串可能的最大大小
capacity 在不重新分配內(nèi)存的情況下,字符串可能的大小
empty 判斷是否為空
operator[] 取第幾個(gè)元素,相當(dāng)于數(shù)組
c_str 取得C風(fēng)格的const char* 字符串
data 取得字符串內(nèi)容地址
operator= 賦值操作符
reserve 預(yù)留空間
swap 交換函數(shù)
insert 插入字符
append 追加字符
push_back 追加字符
operator+= += 操作符
erase 刪除字符串
clear 清空字符容器中所有內(nèi)容
resize 重新分配空間
assign 和賦值操作符一樣
replace 替代
copy 字符串到空間
find 查找
rfind 反向查找
find_first_of 查找包含子串中的任何字符,返回第一個(gè)位置
find_first_not_of 查找不包含子串中的任何字符,返回第一個(gè)位置
find_last_of 查找包含子串中的任何字符,返回最后一個(gè)位置
find_last_not_of 查找不包含子串中的任何字符,返回最后一個(gè)位置
substr 得到字串
compare 比較字符串
operator+ 字符串鏈接
operator== 判斷是否相等
operator!= 判斷是否不等于
operator< 判斷是否小于
operator>> 從輸入流中讀入字符串
operator<< 字符串寫(xiě)入輸出流
getline 從輸入流中讀入一行
C++中String類(lèi)的用法(綜合)
?? ?
之所以拋棄char*的字符串而選用C++標(biāo)準(zhǔn)程序庫(kù)中的string類(lèi),是因?yàn)樗颓罢弑容^起來(lái),不必?fù)?dān)心內(nèi)存是否足夠、字符串長(zhǎng)度等等,而且作為一個(gè)類(lèi)出現(xiàn),他集成的操作函數(shù)足以完成我們大多數(shù)情況下(甚至是100%)的需要。我們可以用 = 進(jìn)行賦值操作,== 進(jìn)行比較,+ 做串聯(lián)(是不是很簡(jiǎn)單?)。我們盡可以把它看成是C++的基本數(shù)據(jù)類(lèi)型。
?? 好了,進(jìn)入正題………
首先,為了在我們的程序中使用string類(lèi)型,我們必須包含頭文件。如下:
?? #include //注意這里不是string.h string.h是C字符串頭文件
1.聲明一個(gè)C++字符串
聲明一個(gè)字符串變量很簡(jiǎn)單:
?? string Str;
這樣我們就聲明了一個(gè)字符串變量,但既然是一個(gè)類(lèi),就有構(gòu)造函數(shù)和析構(gòu)函數(shù)。上面的聲明沒(méi)有傳入?yún)?shù),所以就直接使用了string的默認(rèn)的構(gòu)造函數(shù),這個(gè)函數(shù)所作的就是把Str初始化為一個(gè)空字符串。String類(lèi)的構(gòu)造函數(shù)和析構(gòu)函數(shù)如下:
a)??? string s;? //生成一個(gè)空字符串s
b)??? string s(str) //拷貝構(gòu)造函數(shù) 生成str的復(fù)制品
c)??? string s(str,stridx) //將字符串str內(nèi)“始于位置stridx”的部分當(dāng)作字符串的初值
d)??? string s(str,stridx,strlen) //將字符串str內(nèi)“始于stridx且長(zhǎng)度頂多strlen”的部分作為字符串的初值
e)??? string s(cstr) //將C字符串作為s的初值
f)??? string s(chars,chars_len) //將C字符串前chars_len個(gè)字符作為字符串s的初值。
g)??? string s(num,c) //生成一個(gè)字符串,包含num個(gè)c字符
h)??? string s(beg,end) //以區(qū)間beg;end(不包含end)內(nèi)的字符作為字符串s的初值
i)??? s.~string() //銷(xiāo)毀所有字符,釋放內(nèi)存
都很簡(jiǎn)單,我就不解釋了。
2.字符串操作函數(shù)
?? 這里是C++字符串的重點(diǎn),我先把各種操作函數(shù)羅列出來(lái),不喜歡把所有函數(shù)都看完的人可以在這里找自己喜歡的函數(shù),再到后面看他的詳細(xì)解釋。
a) =,assign()?? //賦以新值
b) swap()?? //交換兩個(gè)字符串的內(nèi)容
c) +=,append(),push_back() //在尾部添加字符
d) insert() //插入字符
e) erase() //刪除字符
f) clear() //刪除全部字符
g) replace() //替換字符
h) + //串聯(lián)字符串
i) ==,!=,<,<=,>,>=,compare()? //比較字符串
j) size(),length()? //返回字符數(shù)量
k) max_size() //返回字符的可能最大個(gè)數(shù)
l) empty()? //判斷字符串是否為空
m) capacity() //返回重新分配之前的字符容量
n) reserve() //保留一定量?jī)?nèi)存以容納一定數(shù)量的字符
o) [ ], at() //存取單一字符
p) >>,getline() //從stream讀取某值
q) <<? //將謀值寫(xiě)入stream
r) copy() //將某值賦值為一個(gè)C_string
s) c_str() //將內(nèi)容以C_string返回
t) data() //將內(nèi)容以字符數(shù)組形式返回
u) substr() //返回某個(gè)子字符串
v)查找函數(shù)
w)begin() end() //提供類(lèi)似STL的迭代器支持
x) rbegin() rend() //逆向迭代器
y) get_allocator() //返回配置器
下面詳細(xì)介紹:
2.1 C++字符串和C字符串的轉(zhuǎn)換
?? C++ 提供的由C++字符串得到對(duì)應(yīng)的C_string的方法是使用data()、c_str()和copy(),其中,data()以字符數(shù)組的形式返回字符串內(nèi)容,但并不添加’/0’。c_str()返回一個(gè)以‘/0’結(jié)尾的字符數(shù)組,而copy()則把字符串的內(nèi)容復(fù)制或?qū)懭爰扔械腸_string或字符數(shù)組內(nèi)。C++字符串并不以’/0’結(jié)尾。我的建議是在程序中能使用C++字符串就使用,除非萬(wàn)不得已不選用c_string。由于只是簡(jiǎn)單介紹,詳細(xì)介紹掠過(guò),誰(shuí)想進(jìn)一步了解使用中的注意事項(xiàng)可以給我留言(到我的收件箱)。我詳細(xì)解釋。
2.2 大小和容量函數(shù)
?? 一個(gè)C++字符串存在三種大小:a)現(xiàn)有的字符數(shù),函數(shù)是size()和length(),他們等效。Empty()用來(lái)檢查字符串是否為空。b)max_size() 這個(gè)大小是指當(dāng)前C++字符串最多能包含的字符數(shù),很可能和機(jī)器本身的限制或者字符串所在位置連續(xù)內(nèi)存的大小有關(guān)系。我們一般情況下不用關(guān)心他,應(yīng)該大小足夠我們用的。但是不夠用的話,會(huì)拋出length_error異常c)capacity()重新分配內(nèi)存之前 string所能包含的最大字符數(shù)。這里另一個(gè)需要指出的是reserve()函數(shù),這個(gè)函數(shù)為string重新分配內(nèi)存。重新分配的大小由其參數(shù)決定,默認(rèn)參數(shù)為0,這時(shí)候會(huì)對(duì)string進(jìn)行非強(qiáng)制性縮減。
還有必要再重復(fù)一下C++字符串和C字符串轉(zhuǎn)換的問(wèn)題,許多人會(huì)遇到這樣的問(wèn)題,自己做的程序要調(diào)用別人的函數(shù)、類(lèi)什么的(比如數(shù)據(jù)庫(kù)連接函數(shù) Connect(char*,char*)),但別人的函數(shù)參數(shù)用的是char*形式的,而我們知道,c_str()、data()返回的字符數(shù)組由該字符串擁有,所以是一種const char*,要想作為上面提及的函數(shù)的參數(shù),還必須拷貝到一個(gè)char*,而我們的原則是能不使用C字符串就不使用。那么,這時(shí)候我們的處理方式是:如果此函數(shù)對(duì)參數(shù)(也就是char*)的內(nèi)容不修改的話,我們可以這樣Connect((char*)UserID.c_str(), (char*)PassWD.c_str()),但是這時(shí)候是存在危險(xiǎn)的,因?yàn)檫@樣轉(zhuǎn)換后的字符串其實(shí)是可以修改的(有興趣地可以自己試一試),所以我強(qiáng)調(diào)除非函數(shù)調(diào)用的時(shí)候不對(duì)參數(shù)進(jìn)行修改,否則必須拷貝到一個(gè)char*上去。當(dāng)然,更穩(wěn)妥的辦法是無(wú)論什么情況都拷貝到一個(gè)char*上去。同時(shí)我們也祈禱現(xiàn)在仍然使用C字符串進(jìn)行編程的高手們(說(shuō)他們是高手一點(diǎn)兒也不為過(guò),也許在我們還穿開(kāi)襠褲的時(shí)候他們就開(kāi)始編程了,哈哈…)寫(xiě)的函數(shù)都比較規(guī)范,那樣我們就不必進(jìn)行強(qiáng)制轉(zhuǎn)換了。
2.3元素存取
?? 我們可以使用下標(biāo)操作符[]和函數(shù)at()對(duì)元素包含的字符進(jìn)行訪問(wèn)。但是應(yīng)該注意的是操作符[]并不檢查索引是否有效(有效索引0~str.length()),如果索引失效,會(huì)引起未定義的行為。而at()會(huì)檢查,如果使用at() 的時(shí)候索引無(wú)效,會(huì)拋出out_of_range異常。
?? 有一個(gè)例外不得不說(shuō),const string a;的操作符[]對(duì)索引值是a.length()仍然有效,其返回值是’/0’。其他的各種情況,a.length()索引都是無(wú)效的。舉例如下:
const string Cstr(“const string”);
string Str(“string”);
Str[3];??? //ok
Str.at(3);? //ok
Str[100]; //未定義的行為
Str.at(100);? //throw out_of_range
Str[Str.length()]? //未定義行為
Cstr[Cstr.length()] //返回 ‘/0’
Str.at(Str.length());//throw out_of_range
Cstr.at(Cstr.length()) throw out_of_range
我不贊成類(lèi)似于下面的引用或指針賦值:
char& r=s[2];
char* p= &s[3];
因?yàn)橐坏┌l(fā)生重新分配,r,p立即失效。避免的方法就是不使用。
2.4比較函數(shù)
?? C++字符串支持常見(jiàn)的比較操作符(>,>=,<,& lt;=,==,!=),甚至支持string與C-string的比較(如 str<”hello”)。在使用>,>=,<,<=這些操作符的時(shí)候是根據(jù)“當(dāng)前字符特性”將字符按字典順序進(jìn)行逐一得比較。字典排序靠前的字符小,比較的順序是從前向后比較,遇到不相等的字符就按這個(gè)位置上的兩個(gè)字符的比較結(jié)果確定兩個(gè)字符串的大小。同時(shí),string(“aaaa”)??? 另一個(gè)功能強(qiáng)大的比較函數(shù)是成員函數(shù)compare()。他支持多參數(shù)處理,支持用索引值和長(zhǎng)度定位子串來(lái)進(jìn)行比較。他返回一個(gè)整數(shù)來(lái)表示比較結(jié)果,返回值意義如下:0-相等〉0-大于 <0-小于。舉例如下:
?? string s(“abcd”);
? ?
?? s.compare(“abcd”); //返回0
?? s.compare(“dcba”); //返回一個(gè)小于0的值
?? s.compare(“ab”); //返回大于0的值
? ?
s.compare(s); //相等
?? s.compare(0,2,s,2,2); //用”ab”和”cd”進(jìn)行比較 小于零
?? s.compare(1,2,”bcx”,2); //用”bc”和”bc”比較。
怎么樣?功能夠全的吧!什么?還不能滿(mǎn)足你的胃口?好吧,那等著,后面有更個(gè)性化的比較算法。先給個(gè)提示,使用的是STL的比較算法。什么?對(duì)STL一竅不通?靠,你重修吧!
2.5 更改內(nèi)容
這在字符串的操作中占了很大一部分。
首先講賦值,第一個(gè)賦值方法當(dāng)然是使用操作符=,新值可以是string(如:s=ns) 、c_string(如:s=”gaint”)甚至單一字符(如:s=’j’)。還可以使用成員函數(shù)assign(),這個(gè)成員函數(shù)可以使你更靈活的對(duì)字符串賦值。還是舉例說(shuō)明吧:
s.assign(str); //不說(shuō)
s.assign(str,1,3);//如果str是”iamangel” 就是把”ama”賦給字符串
s.assign(str,2,string::npos);//把字符串str從索引值2開(kāi)始到結(jié)尾賦給s
s.assign(“gaint”); //不說(shuō)
s.assign(“nico”,5);//把’n’ ‘I’ ‘c’ ‘o’ ‘/0’賦給字符串
s.assign(5,’x’);//把五個(gè)x賦給字符串
把字符串清空的方法有三個(gè):s=””;s.clear();s.erase();(我越來(lái)越覺(jué)得舉例比說(shuō)話讓別人容易懂!)。
string提供了很多函數(shù)用于插入(insert)、刪除(erase)、替換(replace)、增加字符。
先說(shuō)增加字符(這里說(shuō)的增加是在尾巴上),函數(shù)有 +=、append()、push_back()。舉例如下:
s+=str;//加個(gè)字符串
s+=”my name is jiayp”;//加個(gè)C字符串
s+=’a’;//加個(gè)字符
s.append(str);
s.append(str,1,3);//不解釋了 同前面的函數(shù)參數(shù)assign的解釋
s.append(str,2,string::npos)//不解釋了
s.append(“my name is jiayp”);
s.append(“nico”,5);
s.append(5,’x’);
s.push_back(‘a(chǎn)’);//這個(gè)函數(shù)只能增加單個(gè)字符 對(duì)STL熟悉的理解起來(lái)很簡(jiǎn)單
也許你需要在string中間的某個(gè)位置插入字符串,這時(shí)候你可以用insert()函數(shù),這個(gè)函數(shù)需要你指定一個(gè)安插位置的索引,被插入的字符串將放在這個(gè)索引的后面。
s.insert(0,"my name");
s.insert(1,str);
這種形式的insert()函數(shù)不支持傳入單個(gè)字符,這時(shí)的單個(gè)字符必須寫(xiě)成字符串形式(讓人惡心)。既然你覺(jué)得惡心,那就不得不繼續(xù)讀下面一段話:為了插入單個(gè)字符,insert()函數(shù)提供了兩個(gè)對(duì)插入單個(gè)字符操作的重載函數(shù):insert(size_type index,size_type num,chart c)和insert(iterator pos,size_type num,chart c)。其中size_type是無(wú)符號(hào)整數(shù),iterator是char*,所以,你這么調(diào)用insert函數(shù)是不行的:insert(0,1, ’j’);這時(shí)候第一個(gè)參數(shù)將轉(zhuǎn)換成哪一個(gè)呢?所以你必須這么寫(xiě):insert((string::size_type)0,1,’j’)!第二種形式指出了使用迭代器安插字符的形式,在后面會(huì)提及。順便提一下,string有很多操作是使用STL的迭代器的,他也盡量做得和STL靠近。
刪除函數(shù)erase()的形式也有好幾種(真煩!),替換函數(shù)replace()也有好幾個(gè)。舉例吧:
string s="il8n";
s.replace(1,2,"nternationalizatio");//從索引1開(kāi)始的2個(gè)替換成后面的C_string
s.erase(13);//從索引13開(kāi)始往后全刪除
s.erase(7,5);//從索引7開(kāi)始往后刪5個(gè)
2.6提取子串和字符串連接
題取子串的函數(shù)是:substr(),形式如下:
s.substr();//返回s的全部?jī)?nèi)容
s.substr(11);//從索引11往后的子串
s.substr(5,6);//從索引5開(kāi)始6個(gè)字符
把兩個(gè)字符串結(jié)合起來(lái)的函數(shù)是+。(誰(shuí)不明白請(qǐng)致電120)
2.7輸入輸出操作
1.>> 從輸入流讀取一個(gè)string。
2.<< 把一個(gè)string寫(xiě)入輸出流。
另一個(gè)函數(shù)就是getline(),他從輸入流讀取一行內(nèi)容,直到遇到分行符或到了文件尾。
2.8搜索與查找
查找函數(shù)很多,功能也很強(qiáng)大,包括了:
find()
rfind()
find_first_of()
find_last_of()
find_first_not_of()
find_last_not_of()
這些函數(shù)返回符合搜索條件的字符區(qū)間內(nèi)的第一個(gè)字符的索引,沒(méi)找到目標(biāo)就返回npos。所有的函數(shù)的參數(shù)說(shuō)明如下:
第一個(gè)參數(shù)是被搜尋的對(duì)象。第二個(gè)參數(shù)(可有可無(wú))指出string內(nèi)的搜尋起點(diǎn)索引,第三個(gè)參數(shù)(可有可無(wú))指出搜尋的字符個(gè)數(shù)。比較簡(jiǎn)單,不多說(shuō)不理解的可以向我提出,我再仔細(xì)的解答。當(dāng)然,更加強(qiáng)大的STL搜尋在后面會(huì)有提及。
最后再說(shuō)說(shuō)npos的含義,string::npos的類(lèi)型是string::size_type,所以,一旦需要把一個(gè)索引與npos相比,這個(gè)索引值必須是string::size)type類(lèi)型的,更多的情況下,我們可以直接把函數(shù)和npos進(jìn)行比較(如:if(s.find("jia")== string::npos))。
C++中 String的用法 (一)
basic_string::append
向string 的后面加字符或字符串。(比+=, push_back 更靈活)
(1) 向string 的后面加C-string
basic _ string& append( const value _ type* _Ptr );
string s ( "Hello " ); // s= ” Hello ”
const char *c = "Out There ";
s.append ( c ); // s= ” Hello Out There ”
(2) 向string 的后面加C-string 的一部分
basic _ string& append( const value _ type* _Ptr , size _ type _Count );
string s ( "Hello " ); // s= ” Hello ”
const char *c = "Out There ";
s.append ( c , 3 ); // s= ” Hello Out ”
(3) 向string 的后面加string(有兩種方法)
basic _ string& append( const basic _ string& _Str );
string s1 ( "Hello " ), s2 ( "Wide " ), s3( "World " );
s1.append ( s2 ); // s1= ” Hello Wide ”
s1 += s3; // s1= ” Hello Wide World ”
(4) 向string 的后面加string 的一部分 ---A
basic _ string& append( const basic _ string& _Str , size _ type _Off ,
size _ type _Count );
string s1 ( "Hello " ), s2 ( "Wide World " );
s1.append ( s2 , 5 , 5 ); // s1= ” Hello World ”
(5) 向string 的后面加string 的一部分 ---B
template<class InputIterator> basic _ string& append(
InputIterator _First , InputIterator _Last );
string str1f ( "Hello " ), str2f ( "Wide World" );
str1f.append ( str2f.begin ( ) + 5 , str2f.end ( ) );
// s1= ” Hello World ”
(6) 向string 的后面加多個(gè)字符
basic _ string& append( size _ type _Count , value _ type _Ch );
string str1e ( "Hello " );
str1e.append ( 4 , '!' ); // s1= ” Hello !!!! ”
basic_string::assign
給string 賦值。 (比“=”更靈活)
(1) 向string 賦C-string
basic _ string& assign( const value _ type* _Ptr );
string s;
const char *c = "Out There";
s.assign ( c ); // s= ” Out There ”
(2) 向string 賦C-string 的一部分
basic _ string& assign( const value _ type* _Ptr , size _ type _Count );
string s;
const char *c = "Out There";
s.assign ( c , 3 ); // s= ” Out ”
(3) 向string 賦string(有兩種方法)
basic _ string& assign( const basic _ string& _Str );
string s1 ( "Hello" ), s2 ( "Wide" ), s3( "World" );
s1.assign ( s2 ); // s1= ” Wide ”
s1 = s3; // s1= ” World ”
(4) 向string 賦string 的一部分 ---A
basic _ string& assign( const basic _ string& _Str , size _ type off ,
size _ type _Count );
string s1 ( "Hello " ), s2 ( "Wide World " );
s1.assign ( s2 , 5 , 5 ); // s1= ” Hello World ”
(5) 向string 賦string 的一部分 ---B
template<class InIt> basic _ string& assign(
InputIterator _First ,
InputIterator _Last );
string str1f ( "Hello " ), str2f ( "Wide World" );
str1f.assign ( str2f.begin ( ) + 5 , str2f.end ( ) ); // s1= ” Wide World ”
(6) 向string 賦 多個(gè)字符
basic _ string& assign( size _ type _Count , value _ type _Ch );
string str1e ( "Hello " );
str1e.assign ( 4 , '!' ); // s1= ” !!!! ”
C++中String類(lèi)的用法(二)
basic_string::compare
如果所比較的兩個(gè)string 相等,則返回0; 操作string 大于參數(shù)string,返回
正數(shù);操作string 小于參數(shù)string,返回負(fù)數(shù)。
(1) 比較操作string 與 _Str 或C-string _Ptr
int compare( const basic _ string& _Str ) const;
int compare( const value _ type* _Ptr ) const;
int com = s.compare ( sp );
(2) 比較操作string 中 _Pos1 ( 下標(biāo))開(kāi)始的 _Num1 個(gè)字符 與 string _Str
比較操作string 中 _Pos1 ( 下標(biāo))開(kāi)始的 _Num1 個(gè)字符 與 C-string _Ptr
比較操作string 中 Pos1 ( 下標(biāo))開(kāi)始的 Num1 個(gè)字符 與 Str 中 Off ( 下標(biāo))開(kāi)始 Count 個(gè)字
符
int compare( size _ type _Pos1 , size _ type _Num1 , const basic _ string& _Str );
int compare( size _ type _Pos1 , size _ type _Num1 , const value _ type* _Ptr ) const;
int compare( size _ type _Pos1 , size _ type _Num1 , const basic _ string& _Str ,
size _ type _Off , size _ type _Count );
int com1 = s.compare ( 2 , 3 , sp );
int com2 = s.compare ( 2 , 3 , c );
int com3 = s.compare ( 1 , 3 , cs , 3 ,1 );
basic_string::erase
刪除string 中的一個(gè)或幾個(gè)元素。前兩個(gè)成員函數(shù),返回要被刪除的子串的下
一個(gè)元素的iterator; 第三個(gè)函數(shù),返回刪除后的string 的引用。
(1) 刪除string 中從 _ First 到 _ Last 的字符
iterator erase( iterator _First , iterator _Last );
basic_string <char>::iterator s_Iter;
s_Iter = s.erase ( s.begin ( ) + 3 , s.end ( ) - 1 ); // s_Iter=s.end( )
(2) 刪除string 中 _It 所指的字符
iterator erase( iterator _It );
s_Iter = s.erase ( s.begin ( ) + 5 );
(3) 刪除string 中從 _Pos ( 下標(biāo))開(kāi)始的 _Count 個(gè)字符
basic _ string& erase( size _ type _Pos = 0, size _ type _Count = npos );
str = s.erase ( 6 , 8 ); // str 也是 string
basic_string::find
尋找給定的string。返回找到的第一個(gè)string 下標(biāo)值;如果沒(méi)找到則返回npos。
(1) 找一個(gè)character _Ch 。(默認(rèn)從頭找)
size _ type find( value _ type _Ch , size _ type _Off = 0 ) const;
string s ( "Hello Everyone" );
basic_string <char>::size_type index1, index2;
static const basic_string <char>::size_type npos = -1;
index1 = s.find ( "e" , 3 ); // index1=8, 不是 6
index2 = s.find ( "x" ); // index2=-1
if ( indexCh1a != npos ) cout <<indexCh1a << endl;
else cout << "The character 'e' was not found in str1 ." << endl;
(2) 找一個(gè)C-string。(默認(rèn)從頭找)
size _ type find( const value _ type* _Ptr , size _ type _Off = 0 ) const;
string s ( "Let me make this perfectly clear." );
basic_string <char>::size_type index;
const char *c = "perfect";
index = s.find ( c , 5 ); // index=17
(3) 找一個(gè)string。(默認(rèn)從頭找)
size _ type find( const basic _ string& _Str , size _ type _Off = 0 ) const;
string s ( "clearly this perfectly unclear." );
basic_string <char>::size_type index;
string sta ( "clear" );
index = s.find ( sta , 5 ); // index=24
c++中String類(lèi)的用法(三)
basic_string::max_size
返回string 能放的最大元素個(gè)數(shù)。(不同于capacity)
size _ type max _ size( ) const;
basic_string <char>::size_type cap, max;
cap = s.capacity ( );
max = s.max_size ( ); // max=4294967294.
basic_string::rfind
尋找給定的string。返回找到的第一個(gè)string 下標(biāo)值;如果沒(méi)找到則返回npos。
與find 不同的是:rfind 默認(rèn)從npos 開(kāi)始找。其他相同。
basic_string::replace
將原string 中的元素或子串替換。返回替換后的string。
(1)用string 或C-string 代替操作string 中從 _Pos1 開(kāi)始的 _Num1 個(gè)字符
basic _ string& replace( size _ type _Pos1 ,size _ type _Num1 , const value _ type* _Ptr );
basic _ string& replace(size _ type _Pos1 ,size _ type _Num1 ,const basic _ string _Str );
string a,b;
string s ( "AAAAAAAA" );
string s1p ( "BBB" );
const char* cs1p = "CCC" ;
a = s.replace ( 1 , 3 , s1p ); // s= ” ABBBAAAA ”
b = s.replace ( 5 , 3 , cs1p ); // s= ” ABBBACCC ”
(2)用string 中從 _Pos2 開(kāi)始的 _Num2 個(gè)字符,代替操作string 中從 _Pos1 開(kāi)始的 _Num1 個(gè)字符
用C-string 中的 _Num2 個(gè)字符,代替操作string 中從 _Pos1 開(kāi)始的 _Num1 個(gè)字符
basic _ string& replace( size _ type _Pos1 , size _ type _Num1 , const basic _ string& _Str ,
size _ type _Pos2 , size _ type );
basic _ string& replace( size _ type _Pos1 , size _ type _Num1 ,
const value _ type* _Ptr , size _ type _Num2 );
string a, b;
string s ( "AAAAAAAA" );
string s2p ( "BBB" );
const char* cs2p = "CCC";
a = s.replace ( 1 , 3 , s2p , 1 , 2 ); // s= ” ABBAAAA ”
b = s.replace ( 4 , 3 , cs2p , 1 ); // s= ” ABBAC ”
(3)用 _Count 個(gè)character _Ch , 代替操作string 中從 _Pos1 開(kāi)始的 _Num1 個(gè)字符
basic _ string& replace( size _ type _Pos1 , size _ type _Num1 ,
size _ type _Count , value _ type _Ch );
string result;
string s ( "AAAAAAAA" );
char ch = 'C';
result = s.replace ( 1 , 3 , 4 , ch ); // s= ” ACCCCAAAA ”
(4)用string 或C-string ,代替操作string 中從 First0 到 Last0 的字符
basic _ string&replace(iterator First0 ,iterator Last0 , const basic _ string& _Str );
basic _ string&replace(iterator First0 ,iterator _Last0 , const value _ type* _Ptr );
string s ( "AAAAAAAA" ); string s4p ( "BBB" );
const char* cs4p = "CCC";
basic_string<char>::iterator IterF0, IterL0;
IterF0 = s.begin ( ); IterL0 = s.begin ( ) + 3;
string a, b;
a = s.replace ( IterF0 , IterL0 , s4p ); // s= ” BBBAAAAA ”
b = s.replace ( IterF0 , IterL0 , cs4p ); // s= ” CCCAAAAA ”
(5)用string 中從 _Pos2 開(kāi)始的 _Num2 個(gè)字符,代替操作string 中從 First0 到 Last0 的字符
用C-string 中的 _Num2 個(gè)字符,代替操作string 中從 First0 到 Last0 的字符
basic _ string& replace( iterator _First0 , iterator _Last0 ,
const value _ type* _Ptr , size _ type _Num2 );
template<class InputIterator> basic _ string& replace(
iterator _First0 , iterator _Last0 ,
InputIterator _First , InputIterator _Last );
IterF3 = s.begin ( ) + 1; IterL3 = s.begin ( ) + 3;
IterF4 = s.begin ( ); IterL4 = s.begin ( ) + 2;
a = s.replace ( IterF3 , IterL3 , IterF4 , IterL4 );
b = s.replace ( IterF1 , IterL1 , cs5p , 4 );
(6)用 _Count 個(gè)character _Ch , 代替操作string 中從 First0 到 Last0 的字符
basic _ string& replace( iterator _First0 , iterator _Last0 ,
size _ type _Count , value _ type _Ch );
a = s.replace ( IterF2 , IterL2 , 4 , ch );
basic_string::swap(交換兩個(gè)string)
void swap( basic _ string& _Str );
s1.swap ( s2 );
basic_string::substr
返回從 _Off ( 下標(biāo))開(kāi)始的 _Count 個(gè)字符組成的string
basic _ string substr( size _ type _Off = 0, size _ type _Count = npos ) const;
string s("I love you!") , sub;
sub=s.substr( ); // sub= ” I love you! ”
sub=s.substr(1); // sub= ” love you! ”
sub=s.substr(3,4); // sub= ” ove ”
?string函數(shù)用法
@函數(shù)名稱(chēng):????? strdup
函數(shù)原型:????? char *strdup(const char *s)
函數(shù)功能:????? 字符串拷貝,目的空間由該函數(shù)分配
函數(shù)返回:????? 指向拷貝后的字符串指針
參數(shù)說(shuō)明:????? src-待拷貝的源字符串
所屬文件:??? ?
int main()
{
???? char *dup_str, *string="abcde";
???? dup_str=strdup(string);
???? printf("%s", dup_str);
???? free(dup_str);
???? return 0;
}
@函數(shù)名稱(chēng):????? strcpy
函數(shù)原型:????? char* strcpy(char* str1,char* str2);
函數(shù)功能:????? 把str2指向的字符串拷貝到str1中去
函數(shù)返回:????? 返回str1,即指向str1的指針
參數(shù)說(shuō)明:
所屬文件:??? ?
int main()
{
???? char string[10];
???? char *str1="abcdefghi";
???? strcpy(string,str1);
???? printf("the string is:%s/n",string);
???? return 0;
}
@函數(shù)名稱(chēng):????? strncpy
函數(shù)原型:????? char *strncpy(char *dest, const char *src,int count)
函數(shù)功能:????? 將字符串src中的count個(gè)字符拷貝到字符串dest中去
函數(shù)返回:????? 指向dest的指針
參數(shù)說(shuō)明:????? dest-目的字符串,src-源字符串,count-拷貝的字符個(gè)數(shù)
所屬文件:??? ?
int main()
{
???? char string[10];
???? char *str1="abcdefghi";
???? strncpy(string,str1,3);
???? string[3]='/0';
???? printf("%s",string);
???? return 0;
}
@函數(shù)名稱(chēng):????? strcat
函數(shù)原型:????? char* strcat(char * str1,char * str2);
函數(shù)功能:????? 把字符串str2接到str1后面,str1最后的'/0'被取消
函數(shù)返回:????? str1
參數(shù)說(shuō)明:
所屬文件:??? ?
int main()
{
???? char buffer[80];
???? strcpy(buffer,"Hello ");
???? strcat(buffer,"world");
???? printf("%s/n",buffer);
???? return 0;
}
@函數(shù)名稱(chēng):????? strncat
函數(shù)原型:????? char *strncat(char *dest, const char *src, size_t maxlen)
函數(shù)功能:????? 將字符串src中前maxlen個(gè)字符連接到dest中
函數(shù)返回:
參數(shù)說(shuō)明:
所屬文件:??? ?
char buffer[80];
int main()
{
???? strcpy(buffer,"Hello ");
???? strncat(buffer,"world",8);
???? printf("%s/n",buffer);
???? strncat(buffer,"*************",4);
???? printf("%s/n",buffer);
???? return 0;
}
@函數(shù)名稱(chēng):????? strcmp
函數(shù)原型:????? int strcmp(char * str1,char * str2);
函數(shù)功能:????? 比較兩個(gè)字符串str1,str2.
函數(shù)返回:????? str1str2,返回正數(shù).
參數(shù)說(shuō)明:
所屬文件:??? ?
int main()
{
???? char *buf1="aaa", *buf2="bbb", *buf3="ccc";
???? int ptr;
???? ptr=strcmp(buf2, buf1);
???? if(ptr>0)
???????? printf("buffer 2 is greater than buffer 1/n");
???? else
???????? printf("buffer 2 is less than buffer 1/n");
???? ptr=strcmp(buf2, buf3);
???? if(ptr>0)
???????? printf("buffer 2 is greater than buffer 3/n");
???? else
???????? printf("buffer 2 is less than buffer 3/n");
???? return 0;
}
@函數(shù)名稱(chēng):????? strncmp
函數(shù)原型:????? int strncmp(char *str1,char *str2,int count)
函數(shù)功能:????? 對(duì)str1和str2中的前count個(gè)字符按字典順序比較
函數(shù)返回:????? 小于0:str1str2
參數(shù)說(shuō)明:????? str1,str2-待比較的字符串,count-比較的長(zhǎng)度
所屬文件:??? ?
#include
#include
int?? main()
{
???? int ptr;
???? char *buf1="aaabbb",*buf2="bbbccc",*buf3="ccc";
???? ptr=strncmp(buf2,buf1,3);
???? if (ptr>0)
???????? printf("buffer 2 is greater than buffer 1");
???? else
???????? printf("buffer 2 is less than buffer 1");
???????? ptr=strncmp(buf2,buf3,3);
???? if (ptr>0)
???????? printf("buffer 2 is greater than buffer 3");
???? else
???????? printf("buffer 2 is less than buffer 3");
???? return(0);
}
@函數(shù)名稱(chēng):????? strpbrk
函數(shù)原型:????? char *strpbrk(const char *s1, const char *s2)
函數(shù)功能:????? 得到s1中第一個(gè)“同時(shí)也出現(xiàn)在s2中”字符的位置指針
函數(shù)返回:????? 位置指針
參數(shù)說(shuō)明:
所屬文件:??? ?
int main()
{
?? char *p="Find all vowels";
?? while(p)
?? {
???? printf("%s/n",p);
???? p=strpbrk(p+1,"aeiouAEIOU");
?? }
?? return 0;
}
@函數(shù)名稱(chēng):????? strcspn
函數(shù)原型:????? int strcspn(const char *s1, const char *s2)
函數(shù)功能:????? 統(tǒng)計(jì)s1中從頭開(kāi)始直到第一個(gè)“來(lái)自s2中的字符”出現(xiàn)的長(zhǎng)度
函數(shù)返回:????? 長(zhǎng)度
參數(shù)說(shuō)明:
所屬文件:??? ?
int main()
{
???? printf("%d/n",strcspn("abcbcadef","cba"));
???? printf("%d/n",strcspn("xxxbcadef","cba"));
???? printf("%d/n",strcspn("123456789","cba"));
???? return 0;
}
@函數(shù)名稱(chēng):????? strspn
函數(shù)原型:????? int strspn(const char *s1, const char *s2)
函數(shù)功能:????? 統(tǒng)計(jì)s1中從頭開(kāi)始直到第一個(gè)“不來(lái)自s2中的字符”出現(xiàn)的長(zhǎng)度
函數(shù)返回:????? 位置指針
參數(shù)說(shuō)明:
所屬文件:??? ?
int main()
{
???? printf("%d/n",strspn("out to lunch","aeiou"));
???? printf("%d/n",strspn("out to lunch","xyz"));
???? return 0;
}
@函數(shù)名稱(chēng):????? strchr
函數(shù)原型:????? char* strchr(char* str,char ch);
函數(shù)功能:????? 找出str指向的字符串中第一次出現(xiàn)字符ch的位置
函數(shù)返回:????? 返回指向該位置的指針,如找不到,則返回空指針
參數(shù)說(shuō)明:????? str-待搜索的字符串,ch-查找的字符
所屬文件:??? ?
int main()
{
???? char string[15];
???? char *ptr, c='r';
???? strcpy(string, "This is a string");
???? ptr=strchr(string, c);
???? if (ptr)
???????? printf("The character %c is at position: %d/n",c,ptr-string);
???? else
???????? printf("The character was not found/n");
???? return 0;
}
@函數(shù)名稱(chēng):????? strrchr
函數(shù)原型:????? char *strrchr(const char *s, int c)
函數(shù)功能:????? 得到字符串s中最后一個(gè)含有c字符的位置指針
函數(shù)返回:????? 位置指針
參數(shù)說(shuō)明:
所屬文件:??? ?
int main()
{
???? char string[15];
???? char *ptr,c='r';
???? strcpy(string,"This is a string");
???? ptr=strrchr(string,c);
???? if (ptr)
???????? printf("The character %c is at position:%d",c,ptr-string);
???? else
???????? printf("The character was not found");
???? return 0;
C++ String 類(lèi)常用函數(shù)收藏
string類(lèi)的構(gòu)造函數(shù):
string(const char *s);??? //用c字符串s初始化
string(int n,char c);???? //用n個(gè)字符c初始化
此外,string類(lèi)還支持默認(rèn)構(gòu)造函數(shù)和復(fù)制構(gòu)造函數(shù),如string s1;string s2="hello";都是正確的寫(xiě)法。當(dāng)構(gòu)造的string太長(zhǎng)而無(wú)法表達(dá)時(shí)會(huì)拋出length_error異常
string類(lèi)的字符操作:
const char &operator[](int n)const;
const char &at(int n)const;
char &operator[](int n);
char &at(int n);
operator[]和at()均返回當(dāng)前字符串中第n個(gè)字符的位置,但at函數(shù)提供范圍檢查,當(dāng)越界時(shí)會(huì)拋出out_of_range異常,下標(biāo)運(yùn)算符[]不提供檢查訪問(wèn)。
const char *data()const;//返回一個(gè)非null終止的c字符數(shù)組
const char *c_str()const;//返回一個(gè)以null終止的c字符串
int copy(char *s, int n, int pos = 0) const;//把當(dāng)前串中以pos開(kāi)始的n個(gè)字符拷貝到以s為起始位置的字符數(shù)組中,返回實(shí)際拷貝的數(shù)目
string的特性描述:
int capacity()const;??? //返回當(dāng)前容量(即string中不必增加內(nèi)存即可存放的元素個(gè)數(shù))
int max_size()const;??? //返回string對(duì)象中可存放的最大字符串的長(zhǎng)度
int size()const;??????? //返回當(dāng)前字符串的大小
int length()const;?????? //返回當(dāng)前字符串的長(zhǎng)度
bool empty()const;??????? //當(dāng)前字符串是否為空
void resize(int len,char c);//把字符串當(dāng)前大小置為len,并用字符c填充不足的部分string類(lèi)的輸入輸出操作:
string類(lèi)重載運(yùn)算符operator>>? //用于輸入,同樣重載運(yùn)算符operator<<用于輸出操作。
函數(shù)getline(istream &in,string &s);//用于從輸入流in中讀取字符串到s中,以換行符'/n'分開(kāi)。
string的賦值:
string &operator=(const string &s);//把字符串s賦給當(dāng)前字符串
string &assign(const char *s);//用c類(lèi)型字符串s賦值
string &assign(const char *s,int n);//用c字符串s開(kāi)始的n個(gè)字符賦值
string &assign(const string &s);//把字符串s賦給當(dāng)前字符串
string &assign(int n,char c);//用n個(gè)字符c賦值給當(dāng)前字符串
string &assign(const string &s,int start,int n);//把字符串s中從start開(kāi)始的n個(gè)字符賦給當(dāng)前字符串
string &assign(const_iterator first,const_itertor last);//把first和last迭代器之間的部分賦給字符串
string的連接:
string &operator+=(const string &s);//把字符串s連接到當(dāng)前字符串的結(jié)尾
string &append(const char *s);?? //把c類(lèi)型字符串s連接到當(dāng)前字符串結(jié)尾
string &append(const char *s,int n);//把c類(lèi)型字符串s的前n個(gè)字符連接到當(dāng)前字符串結(jié)尾
string &append(const string &s);??? //同operator+=()
string &append(const string &s,int pos,int n); //把字符串s中從pos開(kāi)始的n個(gè)字符連接到當(dāng)前字符串的結(jié)尾
string &append(int n,char c);??????? //在當(dāng)前字符串結(jié)尾添加n個(gè)字符c
string &append(const_iterator first,const_iterator last);//把迭代器first和last之間的部分連接到當(dāng)前字符串的結(jié)尾
string的比較:
bool perator==(const string &s1,const string &s2)const;//比較兩個(gè)字符串是否相等
運(yùn)算符">","<",">=","<=","!="均被重載用于字符串的比較;
int compare(const string &s) const;//比較當(dāng)前字符串和s的大小
int compare(int pos, int n,const string &s)const;//比較當(dāng)前字符串從pos開(kāi)始的n個(gè)字符組成的字符串與s的大小
int compare(int pos, int n,const string &s,int pos2,int n2)const;//比較當(dāng)前字符串從pos開(kāi)始的n個(gè)字符組成的字符串與s中pos2開(kāi)始的n2個(gè)字符組成的字符串的大小
int compare(const char *s) const;
int compare(int pos, int n,const char *s) const;
int compare(int pos, int n,const char *s, int pos2) const;
compare函數(shù)在>時(shí)返回1,<時(shí)返回-1,==時(shí)返回0
string的子串:
string substr(int pos = 0,int n = npos) const;//返回pos開(kāi)始的n個(gè)字符組成的字符串string的交換:
void swap(string &s2);??? //交換當(dāng)前字符串與s2的值
string類(lèi)的查找函數(shù):
int find(char c, int pos = 0) const;//從pos開(kāi)始查找字符c在當(dāng)前字符串的位置
int find(const char *s, int pos = 0) const;//從pos開(kāi)始查找字符串s在當(dāng)前串中的位置
int find(const char *s, int pos, int n) const;//從pos開(kāi)始查找字符串s中前n個(gè)字符在當(dāng)前串中的位置
int find(const string &s, int pos = 0) const;//從pos開(kāi)始查找字符串s在當(dāng)前串中的位置
//查找成功時(shí)返回所在位置,失敗返回string::npos的值
int rfind(char c, int pos = npos) const;//從pos開(kāi)始從后向前查找字符c在當(dāng)前串中的位置
int rfind(const char *s, int pos = npos) const;
int rfind(const char *s, int pos, int n = npos) const;
int rfind(const string &s,int pos = npos) const;
//從pos開(kāi)始從后向前查找字符串s中前n個(gè)字符組成的字符串在當(dāng)前串中的位置,成功返回所在位置,失敗時(shí)返回string::npos的值
int find_first_of(char c, int pos = 0) const;//從pos開(kāi)始查找字符c第一次出現(xiàn)的位置
int find_first_of(const char *s, int pos = 0) const;
int find_first_of(const char *s, int pos, int n) const;
int find_first_of(const string &s,int pos = 0) const;
//從pos開(kāi)始查找當(dāng)前串中第一個(gè)在s的前n個(gè)字符組成的數(shù)組里的字符的位置。查找失敗返回
string::npos
int find_first_not_of(char c, int pos = 0) const;
int find_first_not_of(const char *s, int pos = 0) const;
int find_first_not_of(const char *s, int pos,int n) const;
int find_first_not_of(const string &s,int pos = 0) const;
//從當(dāng)前串中查找第一個(gè)不在串s中的字符出現(xiàn)的位置,失敗返回string::npos
int find_last_of(char c, int pos = npos) const;
int find_last_of(const char *s, int pos = npos) const;
int find_last_of(const char *s, int pos, int n = npos) const;
int find_last_of(const string &s,int pos = npos) const;
int find_last_not_of(char c, int pos = npos) const;
int find_last_not_of(const char *s, int pos = npos) const;
int find_last_not_of(const char *s, int pos,? int n) const;
int find_last_not_of(const string &s,int pos = npos) const;
//find_last_of和find_last_not_of與find_first_of和find_first_not_of相似,只不過(guò)是從后向前查找
?
string類(lèi)的替換函數(shù):
string &replace(int p0, int n0,const char *s);//刪除從p0開(kāi)始的n0個(gè)字符,然后在p0處插入串s
string &replace(int p0, int n0,const char *s, int n);//刪除p0開(kāi)始的n0個(gè)字符,然后在p0處插入字符串s的前n個(gè)字符
string &replace(int p0, int n0,const string &s);//刪除從p0開(kāi)始的n0個(gè)字符,然后在p0處插入串s
string &replace(int p0, int n0,const string &s, int pos, int n);//刪除p0開(kāi)始的n0個(gè)字符,然后在p0處插入串s中從pos開(kāi)始的n個(gè)字符
string &replace(int p0, int n0,int n, char c);//刪除p0開(kāi)始的n0個(gè)字符,然后在p0處插入n個(gè)字符c
string &replace(iterator first0, iterator last0,const char *s);//把[first0,last0)之間的部分替換為字符串s
string &replace(iterator first0, iterator last0,const char *s, int n);//把[first0,last0)之間的部分替換為s的前n個(gè)字符
string &replace(iterator first0, iterator last0,const string &s);//把[first0,last0)之間的部分替換為串s
string &replace(iterator first0, iterator last0,int n, char c);//把[first0,last0)之間的部分替換為n個(gè)字符c
string &replace(iterator first0, iterator last0,const_iterator first, const_iteratorlast);//把[first0,last0)之間的部分替換成[first,last)之間的字符串
string類(lèi)的插入函數(shù):
string &insert(int p0, const char *s);
string &insert(int p0, const char *s, int n);
string &insert(int p0,const string &s);
string &insert(int p0,const string &s, int pos, int n);
//前4個(gè)函數(shù)在p0位置插入字符串s中pos開(kāi)始的前n個(gè)字符
string &insert(int p0, int n, char c);//此函數(shù)在p0處插入n個(gè)字符c
iterator insert(iterator it, char c);//在it處插入字符c,返回插入后迭代器的位置
void insert(iterator it, const_iterator first, const_iterator last);//在it處插入[first,last)之間的字符
void insert(iterator it, int n, char c);//在it處插入n個(gè)字符c
string類(lèi)的刪除函數(shù)
iterator erase(iterator first, iterator last);//刪除[first,last)之間的所有字符,返回刪除后迭代器的位置
iterator erase(iterator it);//刪除it指向的字符,返回刪除后迭代器的位置
string &erase(int pos = 0, int n = npos);//刪除pos開(kāi)始的n個(gè)字符,返回修改后的字符串
string類(lèi)的迭代器處理:
string類(lèi)提供了向前和向后遍歷的迭代器iterator,迭代器提供了訪問(wèn)各個(gè)字符的語(yǔ)法,類(lèi)似于指針操作,迭代器不檢查范圍。
用string::iterator或string::const_iterator聲明迭代器變量,const_iterator不允許改變迭代的內(nèi)容。常用迭代器函數(shù)有:
const_iterator begin()const;
iterator begin();??????????????? //返回string的起始位置
const_iterator end()const;
iterator end();??????????????????? //返回string的最后一個(gè)字符后面的位置
const_iterator rbegin()const;
iterator rbegin();??????????????? //返回string的最后一個(gè)字符的位置
const_iterator rend()const;
iterator rend();??????????????????? //返回string第一個(gè)字符位置的前面rbegin和rend用于從后向前的迭代訪問(wèn),通過(guò)設(shè)置迭代器
string::reverse_iterator,string::const_reverse_iterator實(shí)現(xiàn)
?
字符串流處理:
通過(guò)定義ostringstream和istringstream變量實(shí)現(xiàn),<sstream>頭文件中
例如:
??? string input("hello,this is a test");
??? istringstream is(input);
??? string s1,s2,s3,s4;
??? is>>s1>>s2>>s3>>s4;//s1="hello,this",s2="is",s3="a",s4="test"
??? ostringstream os;
??? os<<s1<<s2<<s3<<s4;
??? cout<<os.str();
3. vector 用法詳解
這篇文章的目的是為了介紹std::vector,如何恰當(dāng)?shù)厥褂盟鼈兊某蓡T函數(shù)等操作。本文中還討論了條件函數(shù)和函數(shù)指針在迭代算法中使用,如在remove_if()和for_each()中的使用。通過(guò)閱讀這篇文章讀者應(yīng)該能夠有效地使用vector容器,而且應(yīng)該不會(huì)再去使用C類(lèi)型的動(dòng)態(tài)數(shù)組了。
?
Vector總覽
vector是C++標(biāo)準(zhǔn)模板庫(kù)中的部分內(nèi)容,它是一個(gè)多功能的,能夠操作多種數(shù)據(jù)結(jié)構(gòu)和算法的模板類(lèi)和函數(shù)庫(kù)。vector之所以被認(rèn)為是一個(gè)容器,是因?yàn)樗軌蛳袢萜饕粯哟娣鸥鞣N類(lèi)型的對(duì)象,簡(jiǎn)單地說(shuō),vector是一個(gè)能夠存放任意類(lèi)型的動(dòng)態(tài)數(shù)組,能夠增加和壓縮數(shù)據(jù)。
為了可以使用vector,必須在你的頭文件中包含下面的代碼:
#include <vector>
vector屬于std命名域的,因此需要通過(guò)命名限定,如下完成你的代碼:
using std::vector;
vector<int> vInts;
?
?
或者連在一起,使用全名:
std::vector<int> vInts;
?
?
建議使用全局的命名域方式:
using namespace std;
?
?
在后面的操作中全局的命名域方式會(huì)造成一些問(wèn)題。vector容器提供了很多接口,在下面的表中列出vector的成員函數(shù)和操作。
?
Vector成員函數(shù)
函數(shù)
?表述
?
c.assign(beg,end)
c.assign(n,elem)
?將[beg; end)區(qū)間中的數(shù)據(jù)賦值給c。
將n個(gè)elem的拷貝賦值給c。
?
c.at(idx)
?傳回索引idx所指的數(shù)據(jù),如果idx越界,拋出out_of_range。
?
c.back()
?傳回最后一個(gè)數(shù)據(jù),不檢查這個(gè)數(shù)據(jù)是否存在。
?
c.begin()
?傳回迭代器重的可一個(gè)數(shù)據(jù)。
?
c.capacity()
?返回容器中數(shù)據(jù)個(gè)數(shù)。
?
c.clear()
?移除容器中所有數(shù)據(jù)。
?
c.empty()
?判斷容器是否為空。
?
c.end()
?指向迭代器中的最后一個(gè)數(shù)據(jù)地址。
?
c.erase(pos)
c.erase(beg,end)
?刪除pos位置的數(shù)據(jù),傳回下一個(gè)數(shù)據(jù)的位置。
刪除[beg,end)區(qū)間的數(shù)據(jù),傳回下一個(gè)數(shù)據(jù)的位置。
?
c.front()
?傳回地一個(gè)數(shù)據(jù)。
?
get_allocator
?使用構(gòu)造函數(shù)返回一個(gè)拷貝。
?
c.insert(pos,elem)
c.insert(pos,n,elem)
c.insert(pos,beg,end)
?在pos位置插入一個(gè)elem拷貝,傳回新數(shù)據(jù)位置。
在pos位置插入n個(gè)elem數(shù)據(jù)。無(wú)返回值。
在pos位置插入在[beg,end)區(qū)間的數(shù)據(jù)。無(wú)返回值。
?
c.max_size()
?返回容器中最大數(shù)據(jù)的數(shù)量。
?
c.pop_back()
?刪除最后一個(gè)數(shù)據(jù)。
?
c.push_back(elem)
?在尾部加入一個(gè)數(shù)據(jù)。
?
c.rbegin()
?傳回一個(gè)逆向隊(duì)列的第一個(gè)數(shù)據(jù)。
?
c.rend()
?傳回一個(gè)逆向隊(duì)列的最后一個(gè)數(shù)據(jù)的下一個(gè)位置。
?
c.resize(num)
?重新指定隊(duì)列的長(zhǎng)度。
?
c.reserve()
?保留適當(dāng)?shù)娜萘俊?br /> ?
c.size()
?返回容器中實(shí)際數(shù)據(jù)的個(gè)數(shù)。
?
c1.swap(c2)
swap(c1,c2)
?將c1和c2元素互換。
同上操作。
?
vector<Elem> c
vector <Elem> c1(c2)
vector <Elem> c(n)
vector <Elem> c(n, elem)
vector <Elem> c(beg,end)
c.~ vector <Elem>()
?創(chuàng)建一個(gè)空的vector。
復(fù)制一個(gè)vector。
創(chuàng)建一個(gè)vector,含有n個(gè)數(shù)據(jù),數(shù)據(jù)均已缺省構(gòu)造產(chǎn)生。
創(chuàng)建一個(gè)含有n個(gè)elem拷貝的vector。
創(chuàng)建一個(gè)以[beg;end)區(qū)間的vector。
銷(xiāo)毀所有數(shù)據(jù),釋放內(nèi)存。
?
?
Vector操作
函數(shù)
?描述
?
operator[]
?返回容器中指定位置的一個(gè)引用。
?
?
創(chuàng)建一個(gè)vector
vector容器提供了多種創(chuàng)建方法,下面介紹幾種常用的。
創(chuàng)建一個(gè)Widget類(lèi)型的空的vector對(duì)象:
vector<Widget> vWidgets;
//???? ------
//????? |
//????? |- Since vector is a container, its member functions
//???????? operate on iterators and the container itself so
//???????? it can hold objects of any type.
?
?
創(chuàng)建一個(gè)包含500個(gè)Widget類(lèi)型數(shù)據(jù)的vector:
vector<Widget> vWidgets(500);
?
?
創(chuàng)建一個(gè)包含500個(gè)Widget類(lèi)型數(shù)據(jù)的vector,并且都初始化為0:
vector<Widget> vWidgets(500, Widget(0));
?
?
創(chuàng)建一個(gè)Widget的拷貝:
vector<Widget> vWidgetsFromAnother(vWidgets);
?
?
向vector添加一個(gè)數(shù)據(jù)
vector添加數(shù)據(jù)的缺省方法是push_back()。push_back()函數(shù)表示將數(shù)據(jù)添加到vector的尾部,并按需要來(lái)分配內(nèi)存。例如:向vector<Widget>中添加10個(gè)數(shù)據(jù),需要如下編寫(xiě)代碼:
for(int i= 0;i<10; i++)
??? vWidgets.push_back(Widget(i));
?
?
獲取vector中制定位置的數(shù)據(jù)
很多時(shí)候我們不必要知道vector里面有多少數(shù)據(jù),vector里面的數(shù)據(jù)是動(dòng)態(tài)分配的,使用push_back()的一系列分配空間常常決定于文件或一些數(shù)據(jù)源。如果你想知道vector存放了多少數(shù)據(jù),你可以使用empty()。獲取vector的大小,可以使用size()。例如,如果你想獲取一個(gè)vector v的大小,但不知道它是否為空,或者已經(jīng)包含了數(shù)據(jù),如果為空想設(shè)置為-1,你可以使用下面的代碼實(shí)現(xiàn):
int nSize = v.empty() ? -1 : static_cast<int>(v.size());
?
?
訪問(wèn)vector中的數(shù)據(jù)
使用兩種方法來(lái)訪問(wèn)vector。
1、?? vector::at()
2、?? vector::operator[]
operator[]主要是為了與C語(yǔ)言進(jìn)行兼容。它可以像C語(yǔ)言數(shù)組一樣操作。但at()是我們的首選,因?yàn)閍t()進(jìn)行了邊界檢查,如果訪問(wèn)超過(guò)了vector的范圍,將拋出一個(gè)例外。由于operator[]容易造成一些錯(cuò)誤,所有我們很少用它,下面進(jìn)行驗(yàn)證一下:
分析下面的代碼:
vector<int> v;
v.reserve(10);
?
for(int i=0; i<7; i++)
??? v.push_back(i);
?
try
{
?int iVal1 = v[7];? // not bounds checked - will not throw
?int iVal2 = v.at(7); // bounds checked - will throw if out of range
}
catch(const exception& e)
{
?cout << e.what();
}
?
?
我們使用reserve()分配了10個(gè)int型的空間,但并不沒(méi)有初始化。如下圖所示:
?
?
?
你可以在這個(gè)代碼中嘗試不同條件,觀察它的結(jié)果,但是無(wú)論何時(shí)使用at(),都是正確的。
?
刪除vector中的數(shù)據(jù)
vector能夠非常容易地添加數(shù)據(jù),也能很方便地取出數(shù)據(jù),同樣vector提供了erase(),pop_back(),clear()來(lái)刪除數(shù)據(jù),當(dāng)你刪除數(shù)據(jù)的時(shí)候,你應(yīng)該知道要?jiǎng)h除尾部的數(shù)據(jù),或者是刪除所有數(shù)據(jù),還是個(gè)別的數(shù)據(jù)。在考慮刪除等操作之前讓我們靜下來(lái)考慮一下在STL中的一些應(yīng)用。
?
Remove_if()算法
現(xiàn)在我們考慮操作里面的數(shù)據(jù)。如果要使用remove_if(),我們需要在頭文件中包含如下代碼::
#include <algorithm>
?
?
???????? Remove_if()有三個(gè)參數(shù):
1、?? iterator _First:指向第一個(gè)數(shù)據(jù)的迭代指針。
2、?? iterator _Last:指向最后一個(gè)數(shù)據(jù)的迭代指針。
3、?? predicate _Pred:一個(gè)可以對(duì)迭代操作的條件函數(shù)。
?
條件函數(shù)
條件函數(shù)是一個(gè)按照用戶(hù)定義的條件返回是或否的結(jié)果,是最基本的函數(shù)指針,或者是一個(gè)函數(shù)對(duì)象。這個(gè)函數(shù)對(duì)象需要支持所有的函數(shù)調(diào)用操作,重載operator()()操作。remove_if()是通過(guò)unary_function繼承下來(lái)的,允許傳遞數(shù)據(jù)作為條件。
例如,假如你想從一個(gè)vector<CString>中刪除匹配的數(shù)據(jù),如果字串中包含了一個(gè)值,從這個(gè)值開(kāi)始,從這個(gè)值結(jié)束。首先你應(yīng)該建立一個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)包含這些數(shù)據(jù),類(lèi)似代碼如下:
#include <functional>
enum findmodes
{
?FM_INVALID = 0,
?FM_IS,
?FM_STARTSWITH,
?FM_ENDSWITH,
?FM_CONTAINS
};
typedef struct tagFindStr
{
?UINT iMode;
?CString szMatchStr;
} FindStr;
typedef FindStr* LPFINDSTR;
?
?
然后處理?xiàng)l件判斷:
class FindMatchingString
??? : public std::unary_function<CString, bool>
{
???
public:
? FindMatchingString(const LPFINDSTR lpFS) : m_lpFS(lpFS) {}
???
? bool operator()(CString& szStringToCompare) const
? {
???? bool retVal = false;
?
???? switch(m_lpFS->iMode)
???? {
???? case FM_IS:
?????? {
???????? retVal = (szStringToCompare == m_lpFDD->szMatchStr);
???????? break;
?????? }
???? case FM_STARTSWITH:
?????? {
???????? retVal = (szStringToCompare.Left(m_lpFDD->szMatchStr.GetLength())
?????????????? == m_lpFDD->szWindowTitle);
???????? break;
?????? }
???? case FM_ENDSWITH:
?????? {
???????? retVal = (szStringToCompare.Right(m_lpFDD->szMatchStr.GetLength())
?????????????? == m_lpFDD->szMatchStr);
???????? break;
?????? }
???? case FM_CONTAINS:
?????? {
???????? retVal = (szStringToCompare.Find(m_lpFDD->szMatchStr) != -1);
???????? break;
?????? }
???? }
???????
???? return retVal;
?}
???????
private:
??? LPFINDSTR m_lpFS;
};
?
?
通過(guò)這個(gè)操作你可以從vector中有效地刪除數(shù)據(jù):
// remove all strings containing the value of
// szRemove from vector<CString> vs.
?
FindStr fs;
fs.iMode = FM_CONTAINS;
fs.szMatchStr = szRemove;
?
vs.erase(std::remove_if(vs.begin(), vs.end(), FindMatchingString(&fs)), vs.end());
?
?
Remove_if()能做什么?
你可能會(huì)疑惑,對(duì)于上面那個(gè)例子在調(diào)用remove_if()的時(shí)候還要使用erase()呢?這是因?yàn)榇蠹也⒉皇煜TL中的算法。Remove(),remove_if()等所有的移出操作都是建立在一個(gè)迭代范圍上的,那么不能操作容器中的數(shù)據(jù)。所以在使用remove_if(),實(shí)際上操作的時(shí)容器里數(shù)據(jù)的上面的。思考上面的例子:
1、?? szRemove = “o”.
2、?? vs見(jiàn)下面圖表中的顯示。
?
觀察這個(gè)結(jié)果,我們可以看到remove_if()實(shí)際上是根據(jù)條件對(duì)迭代地址進(jìn)行了修改,在數(shù)據(jù)的后面存在一些殘余的數(shù)據(jù),那些需要?jiǎng)h除的數(shù)據(jù)。剩下的數(shù)據(jù)的位置可能不是原來(lái)的數(shù)據(jù),但他們是不知道的。
調(diào)用erase()來(lái)刪除那些殘余的數(shù)據(jù)。注意上面例子中通過(guò)erase()刪除remove_if()的結(jié)果和vs.enc()范圍的數(shù)據(jù)。
?
壓縮一個(gè)臃腫的vector
很多時(shí)候大量的刪除數(shù)據(jù),或者通過(guò)使用reserve(),結(jié)果vector的空間遠(yuǎn)遠(yuǎn)大于實(shí)際需要的。所有需要壓縮vector到它實(shí)際的大小。resize()能夠增加vector的大小。Clear()僅僅能夠改變緩存的大小,所有的這些對(duì)于vector釋放內(nèi)存等九非常重要了。如何來(lái)解決這些問(wèn)題呢,讓我們來(lái)操作一下。
我們可以通過(guò)一個(gè)vector創(chuàng)建另一個(gè)vector。讓我們看看這將發(fā)生什么。假定我們已經(jīng)有一個(gè)vector v,它的內(nèi)存大小為1000,當(dāng)我們調(diào)用size()的時(shí)候,它的大小僅為7。我們浪費(fèi)了大量的內(nèi)存。讓我們?cè)谒幕A(chǔ)上創(chuàng)建一個(gè)vector。
std::vector<CString> vNew(v);
cout << vNew.capacity();
?
?
vNew.capacity()返回的是7。這說(shuō)明新創(chuàng)建的只是根據(jù)實(shí)際大小來(lái)分配的空間?,F(xiàn)在我們不想釋放v,因?yàn)槲覀円谄渌胤接玫剿?#xff0c;我們可以使用swap()將v和vNew互相交換一下?
??? vNew.swap(v);
??? cout << vNew.capacity();
??? cout << v.capacity();
?
?
有趣的是:vNew.capacity()是1000,而v.capacity()是7。
現(xiàn)在是達(dá)到我的目的了,但是并不是很好的解決方法,我們可以像下面這么寫(xiě):
??? std::vector<CString>(v).swap(v);
?
你可以看到我們做了什么?我們創(chuàng)建了一個(gè)臨時(shí)變量代替那個(gè)命名的,然后使用swap(),這樣我們就去掉了不必要的空間,得到實(shí)際大小的v。
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)
總結(jié)
以上是生活随笔為你收集整理的STL中map和string, vector 用法详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: C/C++函数调用的几种方式总结
- 下一篇: Aspose.Cells.dll操作ex