提到string,我們先回頭看下C語言中的字符串
C語言中,字符串是以’\0’結(jié)尾的一些字符的集合,為了操作方便,C標(biāo)準(zhǔn)庫中提供了一些str系列的庫函數(shù),
但是這些庫函數(shù)與字符串是分離開的,不太符合OOP的思想,而且底層空間需要用戶自己管理,稍不留神可
能還會越界訪問
在OJ中,有關(guān)字符串的題目基本以string類的類型出現(xiàn),而且在常規(guī)學(xué)習(xí)中,為了簡單、方便、快捷、基本都在使用string類,很少有人去使用C庫中的字符串操作函數(shù)。
讓我們一起來認(rèn)識下string類
1.字符串是表示字符序列的類。
2.標(biāo)準(zhǔn)的字符串類提供了對此類對象的支持,其接口類似于標(biāo)準(zhǔn)字符器的接口,但添加了專門用于操作單字節(jié)字符字符串的設(shè)計特性。
3.string類是使用char(即作為它的字符類型,使用它的默認(rèn)char_traits和分配器類型 )。
4.string類是basic_string模板類的一個實例,它使用char來實例化basic_string模板類,并用char_traits和allocator作為basic_string的默認(rèn)參數(shù)。
總結(jié):
1)string是表示字符串的字符串類
2)該類的接口與常規(guī)容器的接口基本相同,再添加了一些專門用來操作string的常規(guī)操作
3) string在底層實際是:basic_string模板類的別名,typedef basic_string
4)不能操作多字節(jié)或者變長字符的序列
在使用string類時,必須包含#include頭文件以及using namespace std;
若想了解更詳細(xì)內(nèi)容,請查詢正規(guī)文檔: string - C++ Reference (cplusplus.com)
2.string常用接口介紹以下內(nèi)容均根據(jù)官方文檔中對string類的詳細(xì)介紹進(jìn)行整合編寫,如有錯誤,還望各位大佬指出,多多包涵
2.1string類對象的常見構(gòu)造1)string() 功能:構(gòu)造空的string類對象,即空字符串
2)string(const char* s) 功能:用C-string來構(gòu)造string類對象
3)string(size_t n,char c) 功能:string類對象中包含n個字符c
4)string(const string& s) 功能:拷貝構(gòu)造函數(shù)
圖中以四種不同的方式創(chuàng)建了5個string類對象,接下來讓我們分析一下各種創(chuàng)建方式
首先,我們可以看到s1打印在屏幕是一串空字符,而string s1創(chuàng)建時正好沒有給s1內(nèi)容,為一個空字符串;
s2很明顯,以Hello world為內(nèi)容初始化了;s3以5個X來進(jìn)行初始化。 s4和s5通過拷貝構(gòu)造函數(shù)對s2和s3進(jìn)行拷貝,存放的字符串內(nèi)容與其一樣。
2.2string類對象的容量操作1) size 功能:返回字符串有效字符長度
此接口功能簡單,不做過多贅述。
2)length 功能:返回字符串有效字符長度
PS: length與size接口功能一樣,都是返回字符串有效字符長度。
3)capacity 功能:返回空間總大小
這里我們可以看出size接口返回的值與capacity接口返回的值不同,往后我們再詳細(xì)分析原因。
4)empty 功能:檢測字符串是否為空串
圖中g(shù)etline不懂的同學(xué)可以暫時理解為cin/scanf
讓我們測試一下,該接口的功能。
我們可以得知,empty接口功能,當(dāng)字符串為空返回真,不為空則返回假。
5)clear 功能:清空有效字符
很明顯,使用clear接口之后,s1中的字符串內(nèi)容全部清理干凈了。
我們可以將clear理解為一個大掃除,會將目標(biāo)對象中的字符串全部清理干凈,“一個不?!保遣粫淖兛臻g大小。
6)reserve 功能:為字符串預(yù)留空間
第63行中,我們使用reserve接口將s1空間擴(kuò)大到30,但m2的值卻是31,這是為什么?
這里為什么m2的值沒有發(fā)生改變,明明用過了reserve接口?
接下來,讓我們一探究竟
仔細(xì)閱讀,我們會得知,只有當(dāng)n大于當(dāng)前的capacity時,才會對其進(jìn)行預(yù)留空間的操作,并且預(yù)留空間是否正好為n也是未知數(shù),可能會比n大(正如我上面用的測試用例,n為30,預(yù)留空間卻成了31);當(dāng)n小于當(dāng)前的capacity,reserve接口不會做任何事情。
7)resize 功能:將有效字符的個數(shù)改成n個,多出的空間用字符c填充
resize接口與reserve接口就不一樣了
在n小于capacity情況下,都將直接修改你字符串的個數(shù)(不是空間大?。⑶医財嗄愕淖址?;
在n大于capcacity情況下,resize也會幫你擴(kuò)容空間大小,并且你可以選擇是否填充字符來補滿剩余的空間大小。
string類對象的容量操作相關(guān)接口就介紹到這。
注意:
1.size()與length()方法底層實現(xiàn)原理完全相同,引入size()的原因是為了與其他容器的接口保持一致,一般情況下基本都是用size()。
2.clear()只是將string中有效字符清空,不改變底層空間大小。
3.resize(size_t n) 與 resize(size_t n, char c)都是將字符串中有效字符個數(shù)改變到n個,不同的是當(dāng)字符個數(shù)增多時:resize(n)用0來填充多出的元素空間,resize(size_t n, char c)用字符c來填充多出的元素空間。注意:resize在改變元素個數(shù)時,如果是將元素個數(shù)增多,可能會改變底層容量的大小,如果是將元素個數(shù)減少,底層空間大小不變
4.reserve(size_t res_arg=0):為string預(yù)留空間,不改變有效元素個數(shù),當(dāng)reserve的參數(shù)小于string的底層空間總大小時,reserver不會改變?nèi)萘看笮 ?/font>
2.3string類對象的訪問及遍歷操作1)operator[] 功能:返回pos位置的字符,const string類對象調(diào)用
string類中對[]進(jìn)行重載,讓其返回pos位置的字符。 讓string[i]變成數(shù)組一樣(char[i])可以直接通過下標(biāo)訪問
讓我們看下調(diào)試展示,是否能到達(dá)我們所說的效果
很顯然,string[i]正如一個數(shù)組一樣可以通過下標(biāo)i逐一訪問。
2)begin+end
begin接口獲得第一個字符的迭代器,end接口獲取最后一個字符下一個位置的迭代器。
用a記錄下第一個迭代器的位置,用b記錄下最后一個字符下一個位置的迭代器的位置
然后計算b-a得出的結(jié)果是否為該string類字符串的長度呢? 結(jié)果為是,這樣看來迭代器與指針有點異曲同工之妙。
再看下面一部分
正如你想象的一樣,將str里面的內(nèi)容逐一打印出來了。
用for循環(huán)把迭代器的位置從begin位置逐漸向end位置移動,并將其對應(yīng)解引用的字符打印出來,
這樣看來越來越像指針了 :)
3)rbegin+rend
這兩個接口與 begin+end 屬于“逆行”關(guān)系。
rbegin接口返回一個逆向迭代器,指向最后一個字符;rend接口返回一個逆向迭代器,指向第一個元素的前一個位置。
上圖應(yīng)該能讓大家更清楚的理解 “逆行” 關(guān)系。
2.4string類對象的修改操作1) push back 功能:在字符串后尾插入字符c
這與我們之前學(xué)過的數(shù)據(jù)結(jié)構(gòu),棧,隊列里面的pushback一樣,同樣是在數(shù)據(jù)尾部插入一個對應(yīng)的數(shù)據(jù)。
也可以配著循環(huán)玩玩 😃
需要注意的是,push back在字符串空間不夠的時候會自動擴(kuò)容
2)append 功能:在字符串后追加一個字符串
往字符串后追加字符時使用append,可以有多種方式來進(jìn)行操作
3)operator+= 功能:在字符串后追加字符串str
在對于C語言中內(nèi)置類型,我們知道 a+=b,等價于a=a+b
對于string類,要想往后增加字符或字符串是否只能使用上面介紹的兩個接口呢?
那我們是否能將字符串也實現(xiàn)該功能,str1+=str2 ,答案是可以的
4)c_str 功能:返回C格式字符串
5)find+npos 功能:從字符串pos位置開始往后找字符c,返回該字符在字符串中的位置
find即為查找功能,我們?nèi)粝朐谀硞€字符串中查找某個字符用find即可。
有一點需要注意的是,find接口默認(rèn)從字符串首個字符開始查詢,我們也可以對其修改第一次開始查詢的位置。
我們對s1第一次查詢的位置進(jìn)行了修改,在這個位置后面沒有‘y’字符,這個時候編譯器返回了一個隨機值
這個時候我們需要知道,在string類中,存在著npos這樣一個值。
“until the end of the string”
6)rfind 功能:從字符串pos位置開始往前找字符c,返回該字符在字符串中的位置
rfind和find同樣是屬于“逆行”的關(guān)系,rfind就是從字符串末尾開始查詢字符c,與find不同的僅僅就是查詢方向。
7)substr 功能:在str中從pos位置開始,截取n個字符,然后將其返回
注意:
1.在string尾部追加字符時,s.push_back? / s.append(1, c) / s += 'c’三種的實現(xiàn)方式差不多,一般情況下string類的+=操作用的比較多,+=操作不僅可以連接單個字符,還可以連接字符串。
2.對string操作時,如果能夠大概預(yù)估到放多少字符,可以先通過reserve把空間預(yù)留好 。
2.5string類非成員函數(shù)1)operator+ 功能:將各個字符串連接在一起
這個接口可以將“支離破碎”的多個字符串合在一起
可以是定義好的字符串,也可以是未定義的字符串。
2)getline 功能:獲取一行字符串
在C++中cin常來作為輸入,但我們在輸入字符串時,難免會遇到輸入空格的情況,但cin遇到空格/回車時會自動結(jié)束,將\n存放在緩沖區(qū),所以為了避免這個問題,string類中就有g(shù)etline接口,在輸入時即使碰到空格也不會停止,會將空格存放在字符串中。
PS:上面的幾個接口大家了解一下,下面的OJ題目中會有一些體現(xiàn)他們的使用。string類中還有一些其他的操作,這里不一一列舉,大家在需要用到時不明白了查文檔即可。
string類以及相關(guān)常用接口就結(jié)束到這里。
接下來讓我們嘗試模擬string類的實現(xiàn)。**
3.string類的模擬實現(xiàn)為了與庫里的某些函數(shù)命名沖突,我們在自己的命名空間里完成模擬實現(xiàn)string類
PS.以下標(biāo)出的函數(shù)需要特別注意 3.1構(gòu)造函數(shù)需要注意的是這里我們不使用malloc,選擇用new,需要手動將str拷貝到_str中,開辟的空間內(nèi)存也需要多一個用來存放’\0’,string不會自動以’\0’結(jié)束。
3.2重載=記得先進(jìn)行判斷_str是否還留有空間哦,空間不足,需要開辟新的空間,剩余細(xì)節(jié)與上述構(gòu)造函數(shù)相似。
3.3重載[],reserve,resize3.4push_back,append3.5迭代器范圍for循環(huán)
以前覺得迭代器1好像很神秘,但是實現(xiàn)起來就是這么簡單。
3.6insert插入字符
插入字符串
3.7find查找字符
查找字符串
3.8流提取,流輸入4.string模擬實現(xiàn)代碼最后給出全部代碼,供大家參考
#pragma once
#include#include
namespace YYz
{class string
{public:
typedef char* iterator;
iterator begin()
{ return _str;
}
iterator end()
{ return _str + _size;
}
string(const char* str="")//構(gòu)造函數(shù)
{ _size = strlen(str);
_capacity = _size;
_str = new char[_capacity + 1];
strcpy(_str, str);
}
string(const string& s)//拷貝構(gòu)造
{ _str = new char[s._capacity + 1];
_size = s._size;
_capacity = s._capacity;
strcpy(_str, s._str);
}
string& operator=(const string& s)
{ if (_capacity == _size)
{ char* tmp = new char[s._capacity + 1];
strcpy(tmp,s._str);
delete[]_str;
_str = tmp;
_size = s._size;
_capacity = s._capacity;
}
return *this;
}
char& operator[](size_t pos)
{ assert(_size< pos);
return _str[pos];
}
void reserve(size_t n)
{ if (_capacity< n)
{ char* tmp = new char[n + 1];
strcpy(tmp, _str);
delete[]_str;
_str = tmp;
_capacity = n;
}
}
void resize(size_t n,char ch='\0')
{ if (n >_size)
{ reserve(n);
for (size_t i = _size; i< n; ++i)
{_str[i] = ch;
}
}
else
{ _size = n;
_str[n] = '\0';
}
}
void push_back(char ch)
{ if (_size == _capacity)
{ size_t newcapacity = _capacity == 0 ? 4 : 2 * _capacity;
reserve(newcapacity);
}
_str[_size] = ch;
_size++;
_str[_size] = '\n';
}
void append(const char* str)
{ size_t len = strlen(str);
if (_size + len >_capacity)
{ reserve(_size + len);
}
strcpy(_size + _str, str);
_size += len;
}
string& operator+=(char ch)
{ push_back(ch);
return *this;
}
string& operator+=(const char* ch)
{ append(ch);
return *this;
}
string& insert(size_t pos, char ch)
{ assert(pos<= _size);
if (_size == _capacity)
{ size_t newcapacity = _capacity == 0 ? 4: 2 * _capacity;
reserve(newcapacity);
}
size_t end = _size+1;
while (end >pos)
{ _str[end] = _str[end - 1];
end--;
}
_str[pos] = ch;
_size++;
return *this;
}
string& insert(size_t pos, const char* str)
{ int len = strlen(str);
if (_size + len< _capacity)
{ reserve(_size + len);
}
size_t end = _size + len;
while (end >pos + len - 1)
{ _str[end] = _str[end - 1];
end--;
}
strncpy(_str + pos, str, len);
_size += len;
return *this;
}
const char* c_str()
{ return _str;
}
size_t size() const
{ return _size;
}
size_t capacity() const
{ return _capacity;
}
~string()//析構(gòu)函數(shù)
{ delete[] _str;
_str = nullptr;
_size = _capacity = 0;
}
string& erase(size_t pos, size_t len = npos)
{ assert(pos<= _size);
if (len == npos || pos + len >= _size)
{ _str[pos] = '\0';
_size = pos;
}
else
{ strcpy(_str + pos, _str + pos+len);
_size -= len;
}
return *this;
}
size_t find(char ch, size_t pos = 0) const
{ assert(pos< _size);
while (pos< _size)
{ if (_str[pos] == ch)
{return pos;
}
++pos;
}
return npos;
}
size_t find(const char* str, size_t pos = 0) const
{ assert(pos< _size);
const char* ptr = strstr(_str + pos, str);
if (ptr == nullptr)
{ return npos;
}
else
{ return ptr - _str;
}
}
void clear()
{ _size = 0;
_str[0] = '\0';
}
private:
char* _str;
size_t _size;
size_t _capacity;
const static size_t npos = -1;
};
}
ostream& operator<<(ostream& out, const string& s)
{for (size_t i = 0; i< s.size(); ++i)
{out<< s[i];
}
return out;
}
istream& operator>>(istream& in, string& s)
{s.clear();
char buff[128] = {'\0' };
size_t i = 0;
char ch = in.get();
while (ch != ' ' && ch != '\n')
{if (i == 127)
{ // 滿了
s += buff;
i = 0;
}
buff[i++] = ch;
ch = in.get();
}
if (i >0)
{buff[i] = '\0';
s += buff;
}
return in;
}
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧
新聞名稱:【C++】string詳細(xì)介紹及模擬實現(xiàn)string類-創(chuàng)新互聯(lián)
標(biāo)題路徑:http://www.rwnh.cn/article40/dciceo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計、域名注冊、網(wǎng)站收錄、商城網(wǎng)站、品牌網(wǎng)站設(shè)計、品牌網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容