【c++】STL--string-創(chuàng)新互聯(lián)

前言

? 最開(kāi)始我們學(xué)習(xí)c語(yǔ)言的時(shí)候,我們發(fā)現(xiàn)刷題或者寫(xiě)代碼都是比較麻煩的,如果說(shuō)用c語(yǔ)言造一輛車(chē),那么我需要用c語(yǔ)言先把輪子造好--各個(gè)零件,當(dāng)我們?cè)旌弥笤俳M裝。那么c++則是造好了輪子,只需要我們組裝就好了。這里的的STL里有各個(gè)組件,我只要熟悉的掌握,使用即可。

目前創(chuàng)新互聯(lián)已為近1000家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)站空間、網(wǎng)站運(yùn)營(yíng)、企業(yè)網(wǎng)站設(shè)計(jì)、建湖網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。

網(wǎng)上有句話說(shuō):“不懂STL,不要說(shuō)你會(huì)C++”。STL是C++中的優(yōu)秀作品,有了它的陪伴,許多底層的數(shù)據(jù)結(jié)構(gòu)以及算法都不需要自己重新造輪子,站在前人的肩膀上,健步如飛的快速開(kāi)發(fā)。

所以對(duì)于學(xué)習(xí)c++而言,學(xué)好STL是很有必要的。STL統(tǒng)稱為:“Standard TemplateLibrary 標(biāo)準(zhǔn)模板庫(kù)”,STL提供了有六大組件,包括了容器,算法,迭代器,仿函數(shù),適配器以及空間適配器。這篇文章主要是講解STL容器中的string。這些組件雖然聽(tīng)起來(lái)很陌生,但是熟悉過(guò)后你會(huì)發(fā)現(xiàn)其實(shí)就是扮演的角色一樣,名字不一樣而已。

文章的路程大概就是:我們先了解STL,然后再查看標(biāo)準(zhǔn)庫(kù)中的string類,先對(duì)對(duì)他們的使用進(jìn)行理解,最后為了更好的使用和鞏固,在對(duì)string重要的接口進(jìn)行模擬實(shí)現(xiàn)。模擬實(shí)現(xiàn)的時(shí)候進(jìn)行分析,理解。

目錄

前言

STL

什么是STL

STL的版本

STL的缺陷

標(biāo)準(zhǔn)庫(kù)中的string類

了解string類

string類的常用接口說(shuō)明

string類對(duì)象的容量操作

string類對(duì)象的訪問(wèn)及遍歷操作

string類對(duì)象的修改操作

string類非成員函數(shù)

string類的模擬實(shí)現(xiàn)

經(jīng)典的string類問(wèn)題

淺拷貝/深拷貝

string類的模擬實(shí)現(xiàn)


STL 什么是STL

STL(standard template libaray-標(biāo)準(zhǔn)模板庫(kù)):是C++標(biāo)準(zhǔn)庫(kù)的重要組成部分,不僅是一個(gè)可復(fù)用的組件庫(kù),而且 是一個(gè)包羅數(shù)據(jù)結(jié)構(gòu)與算法的軟件框架。

STL的版本

原始版本

Alexander Stepanov、Meng Lee 在惠普實(shí)驗(yàn)室完成的原始版本,本著開(kāi)源精神,他們聲明允許任何人任意 運(yùn)用、拷貝、修改、傳播、商業(yè)使用這些代碼,無(wú)需付費(fèi)。唯一的條件就是也需要向原始版本一樣做開(kāi)源使 用。 HP 版本--所有STL實(shí)現(xiàn)版本的始祖。

P. J. 版本

由P. J. Plauger開(kāi)發(fā),繼承自HP版本,被Windows Visual C++采用,不能公開(kāi)或修改,缺陷:可讀性比較低, 符號(hào)命名比較怪異。

RW版本

由Rouge Wage公司開(kāi)發(fā),繼承自HP版本,被C+ + Builder 采用,不能公開(kāi)或修改,可讀性一般。

SGI版本

由Silicon Graphics Computer Systems,Inc公司開(kāi)發(fā),繼承自HP版 本。被GCC(Linux)采用,可移植性好, 可公開(kāi)、修改甚至販賣(mài),從命名風(fēng)格和編程 風(fēng)格上看,閱讀性非常高。我們后面學(xué)習(xí)STL要閱讀部分源代碼, 主要參考的就是這個(gè)版本。

STL的缺陷

1.STL庫(kù)的更新太慢了。這個(gè)得嚴(yán)重吐槽,上一版靠譜是C++98,中間的C++03基本一些修訂。C++11出 來(lái)已經(jīng)相隔了13年,STL才進(jìn)一步更新。

2. STL現(xiàn)在都沒(méi)有支持線程安全。并發(fā)環(huán)境下需要我們自己加鎖。且鎖的粒度是比較大的。

3. STL極度的追求效率,導(dǎo)致內(nèi)部比較復(fù)雜。比如類型萃取,迭代器萃取。

4. STL的使用會(huì)有代碼膨脹的問(wèn)題,比如使用vector/vector/vector這樣會(huì)生成多份代碼,當(dāng)然這是模板語(yǔ) 法本身導(dǎo)致的。

標(biāo)準(zhǔn)庫(kù)中的string類 了解string類

1. string是表示字符串的字符串類

2. 該類的接口與常規(guī)容器的接口基本相同,再添加了一些專門(mén)用來(lái)操作string的常規(guī)操作。

3. string在底層實(shí)際是:basic_string模板類的別名,typedef basic_string string;

4. 不能操作多字節(jié)或者變長(zhǎng)字符的序列。

在使用string類時(shí),必須包含#include頭文件以及using namespace std;

string類的常用接口說(shuō)明

在標(biāo)準(zhǔn)庫(kù)中string有7個(gè)接口,這里我們主要講解和使用4個(gè),后面模擬實(shí)現(xiàn)也是模擬我們常用的。

default (1)
string();
copy (2)
string (const string& str);
substring (3)
string (const string& str, size_t pos, size_t len = npos);
from c-string (4)
string (const char* s);
from sequence (5)
string (const char* s, size_t n);
fill (6)
string (size_t n, char c);
range (7)
templatestring  (InputIterator first, InputIterator last);

string()

Constructs an?empty?string, with a?length?of zero characters

----構(gòu)造一個(gè)長(zhǎng)度為零個(gè)字符的空字符串。

#include#includeusing namespace std;

int main()
{
	string str;//構(gòu)造空的string類對(duì)象s1

	cout<< str<< endl;

	return 0;
}

string(const char* s)?

Copies the null-terminated character sequence (C-string) pointed by?s.

----復(fù)制s指向的以空字符結(jié)尾的字符序列(C字符串)

#include#includeusing namespace std;

int main()
{
	string str("hello world"); 

	cout<< str<< endl;

	return 0;
}

string(size_t n, char c)?

Fills the string with?nconsecutive copies of character?c

----用字符c的n個(gè)連續(xù)副本填充字符串

#include#includeusing namespace std;

int main()
{
	string str(12,'x'); 

	cout<< str<< endl;

	return 0;
}

string(const string&s)

Constructs a copy of?str.

----構(gòu)造str的副本。

#include#includeusing namespace std;

int main()
{

	string str("hello world");
	string str1(str);

	cout<< str1<< endl;

	return 0;
}
string類對(duì)象的容量操作

size

size_t size() const;

Return length of string--返回字符串有效字符長(zhǎng)度

注意:

Returns the length of the string, in terms of bytes.

This is the number of actual bytes that conform the contents of the?string, which is not necessarily equal to its storage?capacity.

Note that?string?objects handle bytes without knowledge of the encoding that may eventually be used to encode the characters it contains. Therefore, the value returned may not correspond to the actual number of encoded characters in sequences of multi-byte or variable-length characters (such as UTF-8).

----返回字符串的長(zhǎng)度,以字節(jié)為單位。這是符合字符串內(nèi)容的實(shí)際字節(jié)數(shù),不一定等于其存儲(chǔ)容量。

請(qǐng)注意,字符串對(duì)象在不知道最終可能用于編碼其包含的字符的編碼的情況下處理字節(jié)。

因此,返回的值可能不對(duì)應(yīng)于多字節(jié)或可變長(zhǎng)度字符序列(如UTF-8)中編碼字符的實(shí)際數(shù)量

這里的更深層的理解就是:我們都是熟知ASCLL表,我們打印的字符,或者符號(hào)都是被數(shù)字所表示的。因?yàn)橛?jì)算機(jī)是只認(rèn)識(shí)二進(jìn)制,所以這些字符或者符號(hào)都會(huì)變成二進(jìn)制讓計(jì)算機(jī)識(shí)別。世界上有各種語(yǔ)言,所以對(duì)應(yīng)的就有不同的電腦編碼。英文對(duì)應(yīng)的電腦編碼是ASCLL,中文對(duì)應(yīng)的電腦編碼很多時(shí)候就是統(tǒng)一碼

統(tǒng)一碼(Unicode),也叫萬(wàn)國(guó)碼、單一碼,由統(tǒng)一碼聯(lián)盟開(kāi)發(fā),是計(jì)算機(jī)科學(xué)領(lǐng)域里的一項(xiàng)業(yè)界標(biāo)準(zhǔn),包括字符集、編碼方案等。統(tǒng)一碼是為了解決傳統(tǒng)的字符編碼方案的局限而產(chǎn)生的,它為每種語(yǔ)言中的每個(gè)字符設(shè)定了統(tǒng)一并且唯一的二進(jìn)制編碼,以滿足跨語(yǔ)言、跨平臺(tái)進(jìn)行文本轉(zhuǎn)換、處理的要求。

統(tǒng)一碼是國(guó)際組織制定的可以容納世界上所有文字和符號(hào)的字符編碼方案。統(tǒng)一碼用數(shù)字0-0x10FFFF來(lái)映射這些字符,最多可以容納1114112個(gè)字符,或者說(shuō)有1114112個(gè)碼位。碼位就是可以分配給字符的數(shù)字。UTF-8、UTF-16、UTF-32都是將數(shù)字轉(zhuǎn)換到程序數(shù)據(jù)的編碼方案。分別映射為8位,16位,32位長(zhǎng)的整數(shù)。

#include#includeusing namespace std;

int main()
{
	string str("hello world");
	size_t n=str.size();

	cout<< n<< endl;

	return 0;
}

length

size_t length() const;

Return length of string ----返回字符串的長(zhǎng)度

#include#includeint main ()
{
  std::string str ("Test string");
  std::cout<< "The size of str is "<< str.length()<< " bytes.\n";
  return 0;
}

注意:

length與size的實(shí)現(xiàn)時(shí)一樣的,只是命名不一樣,這個(gè)是歷史遺留問(wèn)題,就不用過(guò)多的吐槽,在后面容器中就再也沒(méi)有l(wèi)ength了,只在string中有。

capacity

size_t capacity() const;

Return size of allocated storage----返回空間總大小

#include#includeint main ()
{
  std::string str ("Test string");
  std::cout<< "The size of str is "<< str.length()<< " bytes.\n";
  return 0;
}

empty

bool empty() const;

Test if string is empty----檢測(cè)字符串釋放為空串,是返回true,否則返回false

#include#includeusing namespace std;

int main()
{
	string str("hello world");
	
	if (!str.empty())
	{
		cout<< "hello everyone!"<< endl;
	}
	return 0;
}

clear

void clear();

Clear string----清空有效字符

#include#includeusing namespace std;

int main()
{
	string str("hello world");
	
	str.clear();
	cout<< str<< endl;

	return 0;
}

注意:

clear是清空有效字符但是不清除內(nèi)存,因?yàn)橐话闱闆r是下是內(nèi)存足夠,缺時(shí)間。一般會(huì)選擇增容不會(huì)減少內(nèi)存,增加內(nèi)存會(huì)重新開(kāi)辟一塊內(nèi)存,因?yàn)閮?nèi)存中存在這內(nèi)存碎片。減少內(nèi)存之后,重新寫(xiě)入就會(huì)增加空間,那么就更加耗時(shí),所以一般情況下是不減少內(nèi)存的。

reserve

void reserve (size_t n = 0);

Request a change in capacity-----請(qǐng)求更改容量

Requests that the?string capacity?be adapted to a planned change in?size?to a?length?of up to?ncharacters.----請(qǐng)求字符串容量根據(jù)計(jì)劃的大小更改調(diào)整為最多n個(gè)字符的長(zhǎng)度

If?nis greater than the current?string capacity, the function causes the container to increase its?capacity?to?ncharacters (or greater).

In all other cases, it is taken as a non-binding request to shrink the?string capacity: the container implementation is free to optimize otherwise and leave the?string?with a?capacity?greater than?n.

This function has no effect on the?string length?and cannot alter its content.

----如果n大于當(dāng)前字符串容量,則該函數(shù)使容器將其容量增加到n個(gè)字符(或更大)。在所有其他情況下,它被視為縮小字符串容量的非綁定請(qǐng)求:容器實(shí)現(xiàn)可以自由優(yōu)化,否則將字符串容量保留為大于n。此函數(shù)對(duì)字符串長(zhǎng)度沒(méi)有影響,也不能更改其內(nèi)容。

vs2013

#include#includeusing namespace std;

void TestPushBack()
{
	string s;
	s.reserve(500);
	size_t sz = s.capacity();
	cout<< "capacity changed: "<< sz<< '\n';
	cout<< s.size()<< endl;
	cout<< "making s grow:\n";
	for (int i = 0; i< 1000; ++i)
	{
		s.push_back('c');
		if (sz != s.capacity())
		{
			sz = s.capacity();
			cout<< "capacity changed: "<< sz<< '\n';
		}
	}
}

int main()
{
	TestPushBack();

	return 0;
}

我們發(fā)現(xiàn)在vs2013環(huán)境下,它是以1.5倍擴(kuò)容的

linux下--同樣的代碼

那么在linux下我們發(fā)現(xiàn),它是以2倍擴(kuò)容的

我們知道要插入多少數(shù)據(jù),提前用reserve開(kāi)好空間,避免擴(kuò)容,提高效率

resize

void resize (size_t n);

void resize (size_t n, char c);

Resize string----調(diào)整字符串大小

Resizes the string to a?length?of?ncharacters.

If?nis smaller than the current?string length, the current value is shortened to its first?ncharacter, removing the characters beyond the?nth.

If?nis greater than the current?string length, the current content is extended by inserting at the end as many characters as needed to reach a size of?n. If?cis specified, the new elements are initialized as copies of?c, otherwise, they are?value-initialized characters(null characters).

-----將字符串的長(zhǎng)度調(diào)整為n個(gè)字符。如果n小于當(dāng)前字符串長(zhǎng)度,則將當(dāng)前值縮短為其第一個(gè)n個(gè)字符,刪除第n個(gè)字符以外的字符。如果n大于當(dāng)前字符串長(zhǎng)度,則通過(guò)在末尾插入盡可能多的字符來(lái)擴(kuò)展當(dāng)前內(nèi)容,以達(dá)到n的大小。如果指定了c,則將新元素初始化為c的副本,否則,它們是值初始化字符(空字符)。

#include#includeint main()
{
	std::string str("I like to code in C");
	std::cout<< str<< '\n';

	unsigned sz = str.size();
	std::cout<< sz<< '\n';

	str.resize(sz + 2, '+');//增加兩個(gè)字符‘++’
	std::cout<< str<< '\n';

	str.resize(14);//減少5個(gè)字符
	std::cout<< str<< '\n';
	return 0;
}

string類對(duì)象的訪問(wèn)及遍歷操作

operator[]

char& operator[] (size_t pos);

const char& operator[] (size_t pos) const;

Returns a reference to the character at position?posin the?string.

----返回pos位置的字符,const string類對(duì)象調(diào)用

#include#includeint main()
{
	std::string str("Test string");
	for (int i = 0; i

begin /end

iterator begin();

const_iterator begin() const;

Returns an iterator pointing to the first character of the string

----返回指向字符串第一個(gè)字符的迭代器?

iterator end();

const_iterator end() const;

Returns an iterator pointing to the?past-the-endcharacter of the string.

----返回一個(gè)迭代器,該迭代器指向字符串的結(jié)束字符。

#include#includeint main()
{
	std::string str("Test string");
	for (std::string::iterator it = str.begin(); it != str.end(); ++it)
		std::cout<< *it;
	std::cout<< '\n';

	return 0;
}

rend/rbegin

reverse_iterator rbegin();
const_reverse_iterator rbegin() const;

Return reverse iterator to reverse beginning

----返回反向迭代器以反向開(kāi)始

reverse_iterator rend();
const_reverse_iterator rend() const;

Return reverse iterator to reverse end

----將反向迭代器返回到反向端

#include#includeint main ()
{
  std::string str ("now step live...");
  for (std::string::reverse_iterator rit=str.rbegin(); rit!=str.rend(); ++rit)
    std::cout<< *rit;
  return 0;
}

C++中,迭代器就是一個(gè)類似于指針的對(duì)象,它能夠用來(lái)遍歷C++標(biāo)準(zhǔn)模板庫(kù)容器中的部分或全部元素,每個(gè)迭代器對(duì)象代表容器中的確定的地址。

這里需要注意的是,,對(duì)于string類來(lái)說(shuō),無(wú)論是正向遍歷,還是反向遍歷,下標(biāo)+[]都足夠好用,但是對(duì)于其他容器,對(duì)于那些以鏈表形式連接的數(shù)據(jù)結(jié)構(gòu),如list,map/set等,就不能使用下標(biāo)+[]的方式去訪問(wèn)容器里的元素,所以就需要采用迭代器來(lái)訪問(wèn)這些容器里的元素。

vector--容器

vectorv;
	vector::iterator vit = v.begin();
	while (vit != v.end())
	{
		cout<< *vit<< " ";
		vit++;
	}
	cout<< endl;
string類對(duì)象的修改操作

push_back

void push_back (char c);

ppends character?cto the end of the?string, increasing its?length?by one.

----將字符c追加到字符串的末尾,將其長(zhǎng)度增加1

#include#include#includeusing namespace std;

int main()
{
	string str;
	str.push_back('h');
	str.push_back('e');
	str.push_back('l');
	str.push_back('l');
	str.push_back('o');

	std::cout<< str<< '\n';
	return 0;
}

append

string (1)
string& append (const string& str);
substring (2)
string& append (const string& str, size_t subpos, size_t sublen);
c-string (3)
string& append (const char* s);
buffer (4)
string& append (const char* s, size_t n);
fill (5)
string& append (size_t n, char c);
range (6)
templatestring& append (InputIterator first, InputIterator last);

(1) string

Appends a copy of?str.----追加str的副本

(2) substring

Appends a copy of a substring of?str. The substring is the portion of?strthat begins at the character position?subposand spans?sublencharacters (or until the end of?str, if either?stris too short or if?sublenis?string::npos).

----追加str的子字符串的副本。該子字符串是str的一部分,從字符位置子字符串開(kāi)始,跨越子字符串字符(或直到str結(jié)尾,如果str太短或子字符串為string::npos)

(3) c-string

Appends a copy of the string formed by the null-terminated character sequence (C-string) pointed by?s.

----追加由s指向的以空結(jié)尾的字符序列(C字符串)形成的字符串的副本

(4) buffer

Appends a copy of the first?ncharacters in the array of characters pointed by?s.

----追加由s指向的字符數(shù)組中前n個(gè)字符的副本

(5) fill

Appends?nconsecutive copies of character?c.

----追加n個(gè)字符c的連續(xù)副本。

(6) range

Appends a copy of the sequence of characters in the range?[first,last), in the same order.

----以相同的順序追加范圍[first,last]中字符序列的副本。

#include#includeint main()
{
	std::string str;
	std::string str2 = "Writing ";
	std::string str3 = "print 10 and then 5 more";

	
	str.append(str2);                       // 情況1
	std::cout<< str<< '\n';

	str.append(str3, 6, 3);                   // 情況2
	std::cout<< str<< '\n';

	str.append("dots are cool", 5);          // 情況3
	std::cout<< str<< '\n';

	str.append("here: ");                   // 情況4
	std::cout<< str<< '\n';

	str.append(10u, '.');                    // 情況5
	std::cout<< str<< '\n';

	str.append(str3.begin() + 8, str3.end());  // 情況6
	std::cout<< str<< '\n';

	return 0;
}

operator+=

Append to string----附加到字符串

string (1)
string& operator+= (const string& str);
c-string (2)
string& operator+= (const char* s);
character (3)
string& operator+= (char c);
#include#includeint main()
{
	std::string name("John");
	std::string family("Smith");
	name += " K. ";         // c-string
	name += family;         // string
	name += '\n';           // character

	std::cout<< name;
	return 0;
}

運(yùn)行結(jié)果:John K. Smith

c_str

const char* c_str() const;

Get C string equivalent----獲取等效的C字符串

Returns a pointer to an array that contains a null-terminated sequence of characters (i.e., a C-string) representing the current value of the string object.

This array includes the same sequence of characters that make up the value of the string object plus an additional terminating null-character ('\0') at the end.

----返回指向數(shù)組的指針,該數(shù)組包含表示字符串對(duì)象當(dāng)前值的以空結(jié)尾的字符序列(即C字符串)。

此數(shù)組包含構(gòu)成字符串對(duì)象值的相同字符序列,加上末尾的附加終止空字符(“\0”)。

#include#include#includeint main()
{
	std::string str("Please split this sentence into tokens");//str是一個(gè)類

	char * cstr = new char[str.length() + 1];
	std::strcpy(cstr, str.c_str());				//將字符串返回成char *,然后進(jìn)行拷貝
												//char *strcpy(char *dest, const char *src)
												//  str現(xiàn)在包含str的c字符串副本

	char * p = std::strtok(cstr, " ");			//char *strtok( char *strToken, const char *strDelimit );
												//分解字符串為一組字符串

	while (p != 0)
	{
		std::cout<< p<< '\n';
		p = std::strtok(NULL, " ");
	}

	delete[] cstr;
	return 0;
}

find?+ npos

string (1)
size_t find (const string& str, size_t pos = 0) const;
c-string (2)
size_t find (const char* s, size_t pos = 0) const;
buffer (3)
size_t find (const char* s, size_t pos, size_t n) const;
character (4)
size_t find (char c, size_t pos = 0) const;

Find content in string----在字符串中查找內(nèi)容

static const size_t npos = -1;

npos:Maximum value for size_t----size_t的大值

#include  
#includeusing namespace std;

int main()
{
	string str("There are two needles in this haystack with needles.");
	string str2("needle");

	// different member versions of find in the same order as above:
	size_t found = str.find(str2);
	if (found != string::npos)
		cout<< "first 'needle' found at: "<< found<< '\n';

	found = str.find("needles are small", found + 1, 6);
	if (found != string::npos)
		cout<< "second 'needle' found at: "<< found<< '\n';

	found = str.find("haystack");
	if (found != string::npos)
		cout<< "'haystack' also found at: "<< found<< '\n';

	found = str.find('.');
	if (found != string::npos)
		cout<< "Period found at: "<< found<< '\n';

	// let's replace the first needle:
	str.replace(str.find(str2), str2.length(), "preposition");
	cout<< str<< '\n';

	return 0;
}

r?nd ?

string (1)
size_t rfind (const string& str, size_t pos = npos) const;
c-string (2)
size_t rfind (const char* s, size_t pos = npos) const;
buffer (3)
size_t rfind (const char* s, size_t pos, size_t n) const;
character (4)
size_t rfind (char c, size_t pos = npos) const;

Find last occurrence of content in string----查找字符串中內(nèi)容的最后一次出現(xiàn)

#include#include#includeint main()
{
	std::string str("The sixth sick sheik's sixth sheep's sick.");
	std::string key("sixth");

	std::size_t found = str.rfind(key);//找到sixth第二次出現(xiàn)的位置

	if (found != std::string::npos)
		str.replace(found, key.length(), "seventh");//seventh替換掉二次出現(xiàn)的sixth

	std::cout<< str<< '\n';

	return 0;
}

輸出結(jié)果:The sixth sick sheik's seventh sheep's sick.

substr

string substr (size_t pos = 0, size_t len = npos) const;

Returns a newly constructed?string?object with its value initialized to a copy of a substring of this object-----返回一個(gè)新構(gòu)造的字符串對(duì)象,其值初始化為此對(duì)象的子字符串的副本。

#include#includeint main ()
{
  std::string str="We think in generalities, but we live in details.";
                                           // (quoting Alfred N. Whitehead)

  std::string str2 = str.substr (3,5);     // "think"

  std::size_t pos = str.find("live");      // position of "live" in str

  std::string str3 = str.substr (pos);     // get from "live" to the end

  std::cout<< str2<< ' '<< str3<< '\n';

  return 0;
}

注意:

1. 在string尾部追加字符時(shí),s.push_back(c) / s.append(1, c) / s += 'c'三種的實(shí)現(xiàn)方式差不多,一般 情況下string類的+=操作用的比較多,+=操作不僅可以連接單個(gè)字符,還可以連接字符串。

2. 對(duì)string操作時(shí),如果能夠大概預(yù)估到放多少字符,可以先通過(guò)reserve把空間預(yù)留好

string類非成員函數(shù)

operator+ (string)

string (1)
string operator+ (const string& lhs, const string& rhs);
c-string (2)
string operator+ (const string& lhs, const char*   rhs);
string operator+ (const char*   lhs, const string& rhs);
character (3)
string operator+ (const string& lhs, char          rhs);
string operator+ (char          lhs, const string& rhs);

Concatenate strings?----連接字符串

#include#includeint main()
{
	std::string firstlevel("com");
	std::string secondlevel("cplusplus");
	std::string scheme("http://");
	std::string hostname;
	std::string url;

	hostname = "www. " + secondlevel + '.' + firstlevel;
	url = scheme + hostname;

	std::cout<< url<< '\n';

	return 0;
}

運(yùn)行結(jié)果:http://www. cplusplus.com

operator>>(string)?

istream& operator>>(istream& is, string& str);

Extract string from stream----從流中提取字符串

#include#includeint main()
{
	std::string name;

	std::cout<< "Please, enter your name: ";
	std::cin >>name;
	std::cout<< "Hello, "<< name<< "!\n";

	return 0;
}

operator<< (string)

ostream& operator<< (ostream& os, const string& str);

Insert string into stream----將字符串插入流?

#include#includeint main()
{
	std::string str = "Hello world!";
	std::cout<< str<< '\n';
	return 0;
}

getline (string)

(1)
istream& getline (istream& is, string& str, char delim);
(2)
istream& getline (istream& is, string& str);

Get line from stream into string----從流獲取線到字符串?

#include#includeint main()
{
	std::string name;

	std::cout<< "Please, enter your full name: ";
	std::getline(std::cin, name);
	std::cout<< "Hello, "<< name<< "!\n";

	return 0;
}

relational operators (string)

(1)
bool operator== (const string& lhs, const string& rhs);
bool operator== (const char*   lhs, const string& rhs);
bool operator== (const string& lhs, const char*   rhs);
(2)
bool operator!= (const string& lhs, const string& rhs);
bool operator!= (const char*   lhs, const string& rhs);
bool operator!= (const string& lhs, const char*   rhs);
(3)
bool operator<  (const string& lhs, const string& rhs);
bool operator<  (const char*   lhs, const string& rhs);
bool operator<  (const string& lhs, const char*   rhs);
(4)
bool operator<= (const string& lhs, const string& rhs);
bool operator<= (const char*   lhs, const string& rhs);
bool operator<= (const string& lhs, const char*   rhs);
(5)
bool operator>(const string& lhs, const string& rhs);
bool operator>(const char*   lhs, const string& rhs);
bool operator>(const string& lhs, const char*   rhs);
(6)
bool operator>= (const string& lhs, const string& rhs);
bool operator>= (const char*   lhs, const string& rhs);
bool operator>= (const string& lhs, const char*   rhs);

Relational operators for string----字符串的關(guān)系運(yùn)算符

#include#includeint main()
{
	std::string foo = "alpha";
	std::string bar = "beta";

	if (foo == bar) std::cout<< "foo and bar are equal\n";
	if (foo != bar) std::cout<< "foo and bar are not equal\n";
	if (foo< bar) std::cout<< "foo is less than bar\n";
	if (foo>bar) std::cout<< "foo is greater than bar\n";
	if (foo<= bar) std::cout<< "foo is less than or equal to bar\n";
	if (foo >= bar) std::cout<< "foo is greater than or equal to bar\n";

	return 0;
}

string類的模擬實(shí)現(xiàn) 經(jīng)典的string類問(wèn)題

我們?cè)谀M實(shí)現(xiàn)string的時(shí)候,可以先看看string類的經(jīng)典問(wèn)題。在實(shí)現(xiàn)string類的構(gòu)造、拷貝構(gòu)造、賦值運(yùn)算符重載以及析構(gòu)函數(shù)時(shí),經(jīng)常會(huì)出現(xiàn)深淺拷貝的問(wèn)題。

構(gòu)造String類對(duì)象的錯(cuò)誤:

String(const char* str = "\0") ----錯(cuò)誤示范,"\0"是需要內(nèi)存存放的

String(const char* str = nullptr) ----錯(cuò)誤示范,String是類,地址是不會(huì)指向nullptr

Sring(const char* str = "")----正確示范

構(gòu)造String類對(duì)象時(shí),如果傳遞nullptr指針,可以認(rèn)為程序非法。

淺拷貝的問(wèn)題:

#include#include 
using namespace std;
class String
{
public:
String(const char* str = "")
{
	
	if (nullptr == str)
	{
		assert(false);
		return;
	}

	_str = new char[strlen(str) + 1];
	strcpy(_str, str);
}

~String()
{
	if (_str)
	{
		delete[] _str;
		_str = nullptr;
	}
}

private:
	char* _str;
};
// 測(cè)試
void TestString()
{
	String s1("hello bit!!!");
	String s2(s1);
}

int main()
{
	TestString();

	return 0;
}

在這段代碼中,我們發(fā)現(xiàn)測(cè)試的時(shí)候,開(kāi)始s1傳入字符串是沒(méi)有問(wèn)題的,但是將s1的地址傳入s2時(shí),就會(huì)出現(xiàn)錯(cuò)誤。因?yàn)樵趕2調(diào)用構(gòu)造函數(shù)的時(shí)候,s2中的_str存放的地址也是s1的地址。那么在調(diào)用析構(gòu)函數(shù)的時(shí)候,我們就會(huì)發(fā)現(xiàn)調(diào)用了兩次析構(gòu)函數(shù),第一將_str清除后,s2再調(diào)用析構(gòu)函數(shù)的時(shí)候,此時(shí)_str已經(jīng)是隨機(jī)值,再對(duì)_str進(jìn)行刪除的時(shí)候就會(huì)報(bào)錯(cuò)。

運(yùn)行結(jié)果:

說(shuō)明:上述String類沒(méi)有顯式定義其拷貝構(gòu)造函數(shù)與賦值運(yùn)算符重載,此時(shí)編譯器會(huì)合成默認(rèn)的,當(dāng)用s1構(gòu)造s2時(shí),編譯器會(huì)調(diào)用默認(rèn)的拷貝構(gòu)造。最終導(dǎo)致的問(wèn)題是,s1、s2共用同一塊內(nèi)存空間,在釋放時(shí)同一塊 空間被釋放多次而引起程序崩潰,這種拷貝方式,稱為淺拷貝。

那么什么是深拷貝?什么是淺拷貝呢?

淺拷貝/深拷貝

淺拷貝:也稱位拷貝,編譯器只是將對(duì)象中的值拷貝過(guò)來(lái)。如果對(duì)象中管理資源,最后就會(huì)導(dǎo)致多個(gè)對(duì)象共享同一份資源,當(dāng)一個(gè)對(duì)象銷(xiāo)毀時(shí)就會(huì)將該資源釋放掉,而此時(shí)另一些對(duì)象不知道該資源已經(jīng)被釋放,以為還有效,所以當(dāng)繼續(xù)對(duì)資源進(jìn)項(xiàng)操作時(shí),就會(huì)發(fā)生發(fā)生了訪問(wèn)違規(guī)。

可以采用深拷貝解決淺拷貝問(wèn)題,即:每個(gè)對(duì)象都有一份獨(dú)立的資源,不要和其他對(duì)象共享。

深拷貝:如果一個(gè)類中涉及到資源的管理,其拷貝構(gòu)造函數(shù)、賦值運(yùn)算符重載以及析構(gòu)函數(shù)必須要顯式給出。一般情況都是按照深拷貝方式提供。

string類的模擬實(shí)現(xiàn)
#define _CRT_SECURE_NO_WARNINGS

#includeusing namespace std;
#include 

#define npos -1

namespace bit
{
	class string
	{
	public:
		typedef char* iterator;

	public:
		string(const char* str = "")//構(gòu)造空的string類對(duì)象,即空字符串
		{
			// 構(gòu)造String類對(duì)象時(shí),如果傳遞nullptr指針,可以認(rèn)為程序非法
			if (nullptr == str)
			{
				assert(false);
				return;
			}

			_str = new char[strlen(str) + 1];//擴(kuò)容要加'/0'
			strcpy(_str, str);
		}

		string(const string& s) //拷貝構(gòu)造函數(shù)
			: _str(new char[strlen(s._str) + 1])//初始化列表
		{
			strcpy(_str, s._str);
		}

		string& operator=(const string& s)//字符串賦值
		{
			if (this != &s)
			{
				char* pStr = new char[strlen(s._str) + 1];
				strcpy(pStr, s._str);
				delete[] _str;
				_str = pStr;
			}
			return *this;
		}

		~string()//析構(gòu)函數(shù)
		{
			if (_str)
			{
				delete[] _str;
				_str=nullptr;
			}
		}
		/
		// iterator--迭代器
		iterator begin()//返回到開(kāi)始
		{
			return _str;
		}

		iterator end()//返回到結(jié)束
		{
			return _str + _size;
		}

		/
		// modify--修改

		void push_back(char c)//將字符附加到字符串
		{
			if (_size == _capacity)
				reserve(_capacity * 2);//2倍擴(kuò)容

			_str[_size++] = c;
			_str[_size] = '\0';//++后添加上‘\0’
		}

		string& operator+=(char c)
		{
			push_back(c);
			return *this;
		}

		
		void append(const char* str)
		{
			size_t n = strlen(str);
			if (_size + n >_capacity )
			{
				reserve(_size + n);
			}

			strcpy(_str + _size, str);
			_size += n;

		}
		string& operator+=(const char* str)
		{
			append(str);
			return *this;
		}

		void clear()
		{
			_str[0] = '\0';
			_size = 0;
		}

		void swap(string& s)
		{
			std::swap(_str,s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);

		}

		const char* c_str()const
		{
			return _str;
		}

		/
		// capacity
		size_t size()const
		{
			return _size;
		}
		size_t capacity()const
		{
			return _capacity;
		}

		bool empty()const
		{
			return 0 == _size;
		}

		void resize(size_t newSize, char c = '\0')
		{
			if (newSize >_size)
			{
				// 如果newSize大于底層空間大小,則需要重新開(kāi)辟空間
				if (newSize >_capacity)
				{
					reserve(newSize);
				}

				memset(_str + _size, c, newSize - _size);
			}

			_size = newSize;
			_str[newSize] = '\0';
		}

		void reserve(size_t newCapacity)
		{
			// 如果新容量大于舊容量,則開(kāi)辟空間
			if (newCapacity >_capacity)
			{
				char* str = new char[newCapacity + 1];
				strcpy(str, _str);

				// 釋放原來(lái)舊空間,然后使用新空間
				delete[] _str;
				_str = str;
				_capacity = newCapacity;
			}
		}

		
		// access
		char& operator[](size_t index)
		{
			assert(index< _size);
			return _str[index];
		}

		const char& operator[](size_t index)const
		{
			assert(index< _size);
			return _str[index];
		}

		
		// 作業(yè)
		bool operator<(const string& s)
		{
			return strcmp(c_str(), s.c_str())<0;//需要接受char*
		}
		bool operator<=(const string& s)
		{
			return *this< s || *this == s;
		}
		//復(fù)用前<  ==
		bool operator>(const string& s)
		{
			return !(*this<= s);
		}

		bool operator>=(const string& s)
		{
			return !(*this< s);
		}

		bool operator==(const string& s)
		{
			return strcmp(c_str(), s.c_str()) == 0;
		}

		bool operator!=(const string& s)
		{
			return !(*this == s);
		}

		// 返回c在string中第一次出現(xiàn)的位置

		size_t find(char c, size_t pos = 0) const
		{
			assert(pos< _size);
			while (pos< _size)
			{
				if (_str[pos] == c)
				{
					return pos;
				}
				pos++;
			}
			return npos;
		}

		// 返回子串s在string中第一次出現(xiàn)的位置
		//strstr:返回字符串中首次出現(xiàn)子串的地址
		size_t find(const char* s, size_t pos = 0) const
		{
			assert(pos< _size);
			const char* ptr = strstr(_str + pos, _str);

			if (ptr == nullptr)
			{
				return npos;
			}
			else
			{
				return ptr - _str;
			}
		}

		// 在pos位置上插入字符c/字符串str,并返回該字符的位置
		string& insert(size_t pos, char c)
		{
			assert(pos<= _size);
			if (_size == _capacity)
			{
				size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2;
				reserve(newCapacity);
			}

			//end--后,當(dāng)減到-1時(shí),是size_t類型就會(huì)變成一個(gè)很大的數(shù),故此必須寫(xiě)成int類型,pos也將被強(qiáng)轉(zhuǎn)
			//int end = _size;
			//while (end >= (int)pos)
			//{
			//	_str[end + 1] = _str[end];
			//	end--;
			//}
			size_t end = _size + 1;
			while (end >pos)
			{
				_str[end] = _str[end - 1];
				end--;
			}

			_str[pos] = c;
			++_size;
		}

		string& insert(size_t pos, const char* str)
		{
			assert(pos<= _size);
			size_t len = strlen(str);
			if (_size == _capacity)
			{
				size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2;
				reserve(newCapacity);
			}

			size_t end = _size + len;

			while (end >pos + len - 1)
			{
				_str[end] = _str[end - len];
				end--;
			}

			strncpy(_str + len, str, len);
			return *this;
		}

		// 刪除pos位置上的元素,并返回該元素的下一個(gè)位置
		string& erase(size_t pos, size_t len)
		{
			assert(pos< _size);

			if (len == npos || pos + len >= _size - pos)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				strcpy(_str + pos, _str + pos + len);
				_size -= len;
			}
			return *this;
		}

	private:
		friend ostream& operator<<(ostream& _cout, const bit::string& s);
		friend istream& operator>>(istream& _cin, bit::string& s);

	private:
		char* _str;
		size_t _capacity;
		size_t _size;
	};

	ostream& operator<<(ostream& _cout, const bit::string& s)
	{
		// 不能使用這個(gè), 因?yàn)閟tring的字符串內(nèi)部可能會(huì)包含\0
		// 直接cout時(shí), 是將_str當(dāng)成char*打印的,遇到內(nèi)部的\0時(shí)后序內(nèi)容就不打印了
		//cout<< s._str;
		for (size_t i = 0; i< s.size(); ++i)
		{
			_cout<< s[i];
		}
		return _cout;
	}
}

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧

分享文章:【c++】STL--string-創(chuàng)新互聯(lián)
文章轉(zhuǎn)載:http://muchs.cn/article42/ddcchc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供云服務(wù)器、動(dòng)態(tài)網(wǎng)站網(wǎng)站制作、外貿(mào)建站、Google域名注冊(cè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)