久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

std::string的用法

 綠巨人大兵 2017-07-28
本文主要針對(duì)那些有C語(yǔ)言背景知識(shí),,而現(xiàn)在開(kāi)始使用C++語(yǔ)言編程的程序員,。事實(shí)上,,C++繼承了大多數(shù)c語(yǔ)言的功能,但有些方面還是不得不要留意的,,如new和delete取代了malloc和free,且C++還使用了STL容器類來(lái)靜態(tài)或動(dòng)態(tài)地分配數(shù)組,。本文中要講的是用std::string來(lái)取代char*,將會(huì)演示C風(fēng)格數(shù)組帶來(lái)的一系列問(wèn)題,,及如何使用std::string來(lái)避免這些問(wèn)題。


避免“病態(tài)”的char數(shù)組聲明

當(dāng)聲明一個(gè)char數(shù)組時(shí),,許多程序員都會(huì)這樣做:


char* name = "marius";


乍看起來(lái)好像沒(méi)什么問(wèn)題,,但如果想讓字符串首字符大寫,最簡(jiǎn)單的實(shí)現(xiàn)方法是:


name[0] = 'M';


代碼生成時(shí)沒(méi)有問(wèn)題,,但在運(yùn)行時(shí)會(huì)崩潰,因?yàn)檫@是未定義的行為,,且依賴于編譯器的實(shí)現(xiàn)(在VS2005中,,可通過(guò)編譯,,但在運(yùn)行時(shí)會(huì)崩潰)。對(duì)此的解答是:“marius”是一個(gè)文字上的字符串,,且存儲(chǔ)于程序的數(shù)據(jù)區(qū),“name”只是一個(gè)指向數(shù)組的指針,,因?yàn)榇鎯?chǔ)字符串的數(shù)據(jù)區(qū)為只讀,所以不允許你修改它,。正確的聲明形式應(yīng)該像下面這樣:


const char* name = "marius";


這樣一來(lái),只要試圖修改其中的一個(gè)字符,,都會(huì)被編譯器發(fā)現(xiàn),并拋出一個(gè)錯(cuò)誤:cannot modify a constant variable,。


“令人討厭”的C風(fēng)格方法

可用char[]來(lái)定義一個(gè)定長(zhǎng)的字符數(shù)組:


char name[] = "marius";
name[0] = 'M';


在本例中,,name是一個(gè)7字符的數(shù)組(包括終止符),,其由字符串“marius”進(jìn)行初始化,,具有讀寫權(quán)限,。
現(xiàn)在,試著用strcat()銜接一個(gè)字符串:


char name[] = "marius";
strcat(name, " bancila");


但程序只要一運(yùn)行就會(huì)崩潰,,因?yàn)閟trcat不能確定緩沖區(qū)是否可以裝下追加的字符串,,導(dǎo)致數(shù)組越界破壞了內(nèi)存。
當(dāng)然了,,你也可聲明一個(gè)更大的數(shù)組來(lái)解決這個(gè)問(wèn)題,只要保證它能放下所有的字符就行了,,比如說(shuō),50個(gè)字符長(zhǎng)度應(yīng)該可以放下一個(gè)英文名了:


char name[50] = "marius";
strcat(name, " bancila");


這就行了,,但如果有Carlos Marìa Eduardo García de la Cal Fernàndez Leal Luna Delgado Galván Sanz這樣的名字呢,,而且這只是單個(gè)西班牙名,另外還有內(nèi)存空間浪費(fèi)的問(wèn)題,,如果聲明了100個(gè)字符長(zhǎng)度,平均使用只有20,,那一份十萬(wàn)個(gè)名字的列表,,要浪費(fèi)800萬(wàn)字節(jié)了。


動(dòng)態(tài)分配內(nèi)存

那么接下來(lái)就是尋找動(dòng)態(tài)分配內(nèi)存最合適的方法:


char* name = new char[strlen("marius")+1];
strcpy(name, "marius");


在此例中,,你可重新分配所需的內(nèi)存,,如下所示:


char* temp = new char[strlen(name) + strlen(" bancila") + 1];
strcpy(temp, name);
strcat(temp, " bancila");

delete [] name;
name = temp;


這需要編寫及維護(hù)更多的代碼,另外,,在涉及到類時(shí),情況會(huì)變得更加復(fù)雜,。


確保類中內(nèi)存的正確處理

如果有一個(gè)Person類,它存儲(chǔ)了人名,,你的第一個(gè)反應(yīng)它可能會(huì)像下面這樣:


class Person
{
char* name;
};


好像看上去沒(méi)什么問(wèn)題,,但這個(gè)類還應(yīng)有:

? 一個(gè)構(gòu)造函數(shù),它可以接受一個(gè)字符串來(lái)初始化name,;
? 一個(gè)自定義的拷貝構(gòu)造函數(shù),以確保深拷貝(默認(rèn)的拷貝構(gòu)造函數(shù)由編譯器提供,,它是淺拷貝,也就是說(shuō),,當(dāng)從一個(gè)對(duì)象中復(fù)制全部屬性的值到一個(gè)對(duì)象時(shí),它只復(fù)制了指針,,而不是指向的所有對(duì)象)。
? 一個(gè)自定義的 operator=
? 一個(gè)析構(gòu)函數(shù),,負(fù)責(zé)清理動(dòng)態(tài)分配的內(nèi)存


把這些整合起來(lái)之后,Person類就會(huì)像下面這樣:


class Person
{
char* name;
public:
Person(const char* str)
{
name = new char [strlen(str)+1];
strcpy(name, str);
}

Person(const Person& p)
{
name = new char [strlen(p.name)+1];
}

Person& operator=(const Person& p)
{
if(this != &p)
{
delete [] name;

name = new char [strlen(p.name)+1];
strcpy(name, p.name);
}

return *this;
}

~Person()
{
delete [] name;
}
};


還是std::string省事

標(biāo)準(zhǔn)模板庫(kù)(STL)提供了一個(gè)std::string類,,其是std::basic_string的一個(gè)特化,它是一個(gè)容器類,,可把字符串當(dāng)作普通類型來(lái)使用,并支持比較,、連接、遍歷,、STL算法,、復(fù)制,、賦值等等操作,這個(gè)類定義在<string>頭文件中,。

使用std::string的好處在于:

1、 易于分配,、復(fù)制及連接。

std::string name = "marius";  // 由賦值進(jìn)行初始化
name += " bancila";           // 連接
std::string copy = name;      // 復(fù)制


2,、 可用length()或size()方法確定字符串的長(zhǎng)度,,這兩個(gè)方法是一樣的,,第二個(gè)方法只是為了保持STL容器類的一致性,。

std::string name = "marius";
std::cout << "length=" << name.length() << std::endl;
std::cout << "length=" << name.size()   << std::endl;


3、 檢查是否為空值,。

std::string name;
if(name.empty())
std::cout << "empty string";


4,、 支持比較。

if(name == "marius")
{
}

if(name.compare("marius") == 0)
{
}
方法campre進(jìn)行大小寫敏感的比較,,以確定兩個(gè)字符串是否相等,或其中一個(gè)在詞典順序上小于另一個(gè),。它的返回值與strcmp()的返回值代表的意義一樣:負(fù)值表示操作數(shù)小于參數(shù)字符串,而正值表示操作系統(tǒng)數(shù)大于它,,0表示相等,。另外,,還有6個(gè)重載版本可允許比較字符串的某一部分:


if(name.compare(0, 3, "mar") == 0)
{
std::cout << "match";
}


5,、 重載操作符 << 和 >>,可從流中讀寫字符串,。

std::string name;
std::cin  >> name;    // 從控制臺(tái)中讀name
std::cout << name;    // 向控制臺(tái)寫name


6,、 易于訪問(wèn)字符串中的字符。

std::string name = "marius";
name[0] = 'M';
name[name.length()-1] = 'S';


7,、 遍歷所有字符,這可由C風(fēng)格的索引或STL迭代子來(lái)完成(如果無(wú)需修改,,應(yīng)使用const_iterator)。

std::string name = "marius";

for(size_t i = 0; i < name.length(); ++i)
std::cout << name[i];

for(std::string::const_iterator cit = name.begin(); cit != name.end(); ++cit)
std::cout << *cit;

for(std::string::iterator it = name.begin();it != name.end(); ++it)
*it = toupper(*it);


8,、 刪除字符串的某一部分,。

std::string name = "marius bancila";
// 刪除第6個(gè)元素之后的所有東西
name.erase(6, name.length() - 6);


9、 在指定位置插入字符串或字符,。

std::string name = "marius";
// 在結(jié)尾插入
name.insert(name.length(), " bancila");
name.insert(name.length(), 3, '!');


10,、在字符串結(jié)尾插入其他元素。

std::string name = "marius";
name.push_back('!');


11,、兩個(gè)字符串值的快速交換。

std::string firstname = "bancila";
std::string lastname = "marius";
firstname.swap(lastname);

std::cout << firstname << ' ' << lastname << std::endl;


12,、使用c_str()方法只讀訪問(wèn)其內(nèi)部字符數(shù)組緩沖區(qū),可在接受字符指針(是否const都行)作參數(shù)的函數(shù)中使用std::string對(duì)象,。

void print(const char* name)
{
std::cout << name << std::endl;
}

std::string name = "marius";
print(name.c_str());

void makeupper(char* array, int len)
{
for(int i = 0; i < len; ++i)
array[i] = toupper(array[i]);
}

std::string name = "marius";
makeupper(&name[0], name.length());


13,、使用STL算法

std::string name = "marius";
// 使字符串全為大寫
std::transform(name.begin(), name.end(), name.begin(),toupper);
std::string name = "marius";
// 升序排列字符串
std::sort(name.begin(), name.end());
std::string name = "marius";
// 反轉(zhuǎn)字符串
std::reverse(name.begin(), name.end());
bool iswhitespace(char ch)
{
return  ch == ' ' || ch == '/t' || ch == '/v' ||
ch == '/r' || ch == '/n';
}

std::string name = " marius  ";
// 刪除空白字符
std::string::iterator newend = std::remove_if(name.begin(), name.end(), iswhitespace);
name.erase(newend);


14、也可用頭文件<sstream>中的std::stringstream來(lái)構(gòu)建字符串,。

std::stringstream strbuilder;
strbuilder << "1 + 1 = " << 1+1;
std::string str = strbuilder.str();


來(lái)回顧一下前面的Person類,,如果用std::string替換了char*,那么剩下的工作只需編寫一個(gè)構(gòu)造函數(shù)就行了,,其他的由編譯器來(lái)完成,在本例中,,復(fù)制字符串時(shí)使用了淺拷貝,,這足夠了,因?yàn)檫@個(gè)動(dòng)作觸發(fā)了std::string的operator=,,它會(huì)正確地復(fù)制字符串,。


class Person
{
std::string name;
public:
Person(const std::string& str)
{
name = str;
}
};

Person p1("marius");
// works because std::string has a constructor that takes a const
// char*

Person p2("bancila");
p1 = p2;


結(jié)論

本文既不是std::string的文檔,,也不是其輔導(dǎo)書,,只是懇求大家使用std::string。用標(biāo)準(zhǔn)模板庫(kù)中的std::string來(lái)取代C風(fēng)格數(shù)組可使代碼看上去更簡(jiǎn)潔,、更自然、更易于閱讀及維護(hù),,也不必?fù)?dān)心動(dòng)態(tài)內(nèi)存分配等問(wèn)題,由此可忽略一些不必要的細(xì)節(jié)問(wèn)題(如內(nèi)存管理),,而集中精力于編程的重要方面,試下吧,。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多