一、標準庫中的string類
1.string類
字符串的表示字符序列的類
標準的字符串類提供了對此類對象的支持,其接口類似于標準字符容器的接口,但添加了專門用于操作
單字節字符字符串的設計特性。
string類是使用char(即作為它的字符類型,使用它的默認char_traits和分配器類型(關于模板的更多信
息,請參閱basic_string)。
string類是basic_string模板類的一個實例,它使用char來實例化basic_string模板類,并用char_traits
和allocator作為basic_string的默認參數(根于更多的模板信息請參考basic_string)。
注意,這個類獨立于所使用的編碼來處理字節:如果用來處理多字節或變長字符(如UTF-8)的序列,這個
類的所有成員(如長度或大小)以及它的迭代器,將仍然按照字節(而不是實際編碼的字符)來操作。
2.string類中的常用接口說明+模擬實現
2.1 string類對象的常見構造+模擬實現
代碼演示:
#include<iostream> #include<string> using namespace std; int main() { string s1; string s4("hello world"); string s5("hello world", 7); string s6(10, 'x'); string s2(s4); string s3(s4, 6, 3); cout << "s1:"<< s1.c_str() << endl; cout << "s4:" << s4.c_str() << endl; cout << "s5:" << s5.c_str() << endl; cout << "s6:" << s6.c_str() << endl; cout << "s2:" << s2.c_str() << endl; cout << "s3:" << s3.c_str() << endl; }
運行結果:
模擬實現
由于上面有些接口不常用,所以我就模擬實現了一部分常用的接口
string (const char* s)
namespace cxy { class string { public: string(const char*s = "") { if (s==nullptr) return; _size = strlen(s); _capacity = _size; _str = new char[_capacity + 1]; strcpy(_str, s); } const char* c_str() { return _str; } private: size_t _size; size_t _capacity; char* _str; }; }
string (const string& str)
void swap (string& str)
namespace cxy { class string { public: void swap(string& str) { //下面的swap會調用庫里面的接口 ::swap(_size, str._size); ::swap(_capacity, str._capacity); ::swap(_str, str._str); } string(const char*s = "") { if (s==nullptr) return; _size = strlen(s); _capacity = _size; _str = new char[_capacity + 1]; strcpy(_str, s); } string(const string& str) :_str(nullptr), _size(0), _capacity(0) { string tmp(str._str); swap(tmp); } char* c_str() { return _str; } private: size_t _size; size_t _capacity; char* _str; }; }
2.2 string類對象的容量操作+模擬實現
代碼演示:
int main() { string s1("hello world"); cout <<"s1.size(): " <<s1.size() << endl; cout <<"s1.length(): "<< s1.length() << endl; cout <<"s1.capacity(): "<<s1.capacity() << endl; cout <<"s1:"<< s1 << endl; cout << endl; s1.clear(); cout <<"s1:"<< s1 << endl; cout << "s1.size(): " << s1.size() << endl; cout << "s1.capacity(): " << s1.capacity() << endl; cout << endl; s1 = "hello world"; cout << "s1:" << s1 << endl; cout << "s1.size(): " << s1.size() << endl; cout << "s1.capacity(): " << s1.capacity() << endl; s1.resize(17,'x'); //當n>capacity,則擴容,并且把0~27上位置的空余位置填充‘字符' cout << "s1:" << s1 << endl; cout << "s1.size(): " << s1.size() << endl; cout << "s1.capacity(): " << s1.capacity() << endl; s1.resize(27, 'x'); //當size<n<capacity,則把0~27上位置的空余位置填充‘字符' cout << "s1:" << s1 << endl; cout << "s1.size(): " << s1.size() << endl; cout << "s1.capacity(): " << s1.capacity() << endl; s1.resize(5, 'x'); //當n<size,則只保留n個‘字符',空間大小不變 cout << "s1:" << s1 << endl; cout << "s1.size(): " << s1.size() << endl; cout << "s1.capacity(): " << s1.capacity() << endl; cout << endl; string s2("hello world"); s2.reserve(5); //當n<=capacity時,空間大小不變,且不改變數據內容 cout << "s2:" << s2 << endl; cout << "s2.size(): " << s2.size() << endl; cout << "s2.capacity(): " << s2.capacity() << endl; s2.reserve(100); //當n>capacity時,空間會增大 cout << "s2:" << s2 << endl; cout << "s2.size(): " << s2.size() << endl; cout << "s2.capacity(): " << s2.capacity() << endl; }
運行結果:
得知:
reserve和resize的區別:reserve不會影響內容,resize會影響內容。
模擬實現
size_t size() const
返回字符串的有效長度
namespace cxy { class string { public: size_t size()const { return _size; } private: size_t _size; size_t _capacity; char* _str; }; }
size_t capacity() const
返回空間的大小
namespace cxy { class string { public: size_t capacity()const { return _capacity; } private: size_t _size; size_t _capacity; char* _str; }; }
bool empty() const
檢測字符串釋放為空串,是返回true,否則返回false
namespace cxy { class string { public: bool empty()const { return _str == 0; } private: size_t _size; size_t _capacity; char* _str; }; }
void clear()
清空有效字符 ,不會改變容量
namespace cxy { class string { public: void clear() { _size = 0; _str[_size] = '\0'; } private: size_t _size; size_t _capacity; char* _str; }; }
void reserve (size_t n = 0)
請求改變容量 ,此功能對字符串長度沒有影響,無法改變其內容
如果 n 大于當前字符串容量,則該函數會導致容器將其容量增加到 n 字符(或更大)
n小于當前字符串容量時,不會發生改變
namespace cxy { class string { public: void reserve(size_t n=0) { if (n > _capacity) { char *tmp = new char[n + 1]; strncpy(tmp,_str,_size+1); delete[]_str; _str = tmp; _capacity = n; } private: size_t _size; size_t _capacity; char* _str; }; }
補充:strncpy是C語言中的函數
char * strncpy ( char * destination, const char * source, size_t num )
功能:
- 將source中的字符串復制到destination中,且復制num個字符個數,如果在沒有復制完num個字符之前,找到了source的末尾,則目標填充零,直到向其編寫了總共num字符。
- 如果來source中的字符有效長度大于數字,則目的地末尾不會隱含任何空字符('\0')。
- 因此,在這種情況下,目的地不應被視為無效終止的 C 字符串(因此讀取它將溢出,所以這種時候記得要在末尾添加'\0')。
void resize (size_t n, char c)
void resize (size_t n)
將有效字符的個數該成n個,多出的空間用字符c填充
- 將字符串大小重新變為n字符的長度。
- 如果 n 小于當前字符串長度,則當前值將縮短為其第一個 n 字符,從而刪除 n 之外的字符。
- 如果 n 大于當前字符串長度,則通過在末尾插入盡可能多的字符c以達到 n 的大小來擴展當前內容。
- 如果指定c,則新元素初始化為c的副本,否則,它們是值初始化字符(空字符)。
namespace cxy { class string { public: void resize(size_t n,char c='\0') { if (n<_size) { _size = n; _str[_size] = '\0'; } else { if (n > _capacity) { reserve(n); } memset(_str + _size, c, n - _size); _size = n; _str[_size] = '\0'; } private: size_t _size; size_t _capacity; char* _str; }; }
補充:memset是C語言中的函數
void * memset ( void * ptr, int value, size_t num )
功能:
- 將value傳到prt中,以第一個位置開始傳,傳num個,傳完為止。
總結
- size()與length()方法底層實現原理完全相同,引入size()的原因是為了與其他容器的接口保持一致,一般情況下基本都是用size()。
-
clear()只是將string中有效字符清空,
不改變底層空間大小。
-
resize(size_t n) 與 resize(size_t n, char c)都是將字符串中有效字符個數改變到n個,不同的是當字符個數增多時:resize(n)用0來填充多出的元素空間,resize(size_t n, char c)用字符c來填充多出的元素空間。
注意:resize在改變元素個數時,如果是將元素個數增多,可能會改變底層容量的大
-
reserve(size_t res_arg=0):為string預留空間,不改變有效元素個數,當
reserve的參數小于string的底層空間總大小時,reserver不會改變容量大小。
2.3 string類對象的訪問及遍歷操作+模擬實現
代碼演示:
int main() { string s("hello world"); cout << "operator[] :"; for (size_t i = 0; i < s.size(); i++) cout << s[i] ; cout << endl; //迭代器 string::iterator it = s.begin(); cout << "iterator :"; while (it != s.end()) { cout << *it ; ++it; } cout << endl; //范圍for cout << "范圍for :"; for (auto ch : s) { cout << ch ; } cout << endl; }
模擬實現
const char& operator[] (size_t pos) const
namespace cxy { class string { public: const char& operator[](size_t pos)const { assert(pos < _size); return _str[pos]; } private: size_t _size; size_t _capacity; char* _str; }; }
iterator begin() iterator end()
namespace cxy { class string { public: typedef char* iterator; iterator begin() { return _str; } iterator end() { return _str+_size; } private: size_t _size; size_t _capacity; char* _str; }; }
C++11:范圍for
在這里不實現,知道怎么用就行
2.4 string類對象的修改操作+模擬實現
代碼演示:
int main() { string s("hello world"); s.push_back('K'); cout << s << endl; s.append("SSSSS"); cout << s << endl; s += "FF"; cout << s << endl; cout << s.find("KSS") << endl; s.erase(11, 8); cout << s << endl; }
運行結果:
模擬實現:只實現了一些常用的接口
void push_back (char c)
在字符串后面插入字符c
namespace cxy { class string { public: void push_back(char c) { if (_size == _capacity) { reserve(_capacity * 2); } _str[_size] = c; _str[_size+1] = '\0'; _size++; } private: size_t _size; size_t _capacity; char* _str; }; }
string& append (const char*s)
在字符串后面追加字符串s
namespace cxy { class string { public: string &append(const char*s) { size_t len = strlen(s)+_size; if (len > _capacity) { reserve(len); } strncpy(_str + _size, s, len - _size+1); _size = len; return *this; } private: size_t _size; size_t _capacity; char* _str; }; }
string& operator+= (const char* s)
在字符串后面追加字符串s
namespace cxy { class string { public: string& operator+=(const char*s) { append(s); return *this; } private: size_t _size; size_t _capacity; char* _str; }; }
const char* c_str() const
返回c格式的字符串
namespace cxy { class string { public: const char* c_str()const { return _str; } private: size_t _size; size_t _capacity; char* _str; }; }
size_t find (const char* s, size_t pos = 0) const
從字符串pos位置開始往后找字符串s,返回該字符串s在字符串中的位置
namespace cxy { class string { public: size_t find(const char*s,size_t pos=0)const { char *str = _str+pos; while (*str) { char* str_s = str; const char* tmp = s; while (*str_s&&*tmp==*str_s) { tmp++; str_s++; } if (*tmp=='\0') return str - _str; else str++; } return -1; } private: size_t _size; size_t _capacity; char* _str; }; }
string& erase (size_t pos = 0, size_t len = npos)
擦除字符串的一部分,減少其長度
static const size_t npos = 0; namespace cxy { class string { public: string &erase(size_t pos = 0, size_t len = npos) { assert(pos < _size); if (len+pos >= _size) { _str[pos] = '\0'; _size = pos; } else { strcpy(_str + pos, _str + pos + len); _size -= len; } return *this; } private: size_t _size; size_t _capacity; char* _str; }; }
2.5 string類非成員函數+模擬實現
模擬實現
istream& operator>> (istream& is, string& str)
namespace cxy { class string { public: private: size_t _size; size_t _capacity; char* _str; }; istream& operator >> (istream& is, string& str) { str.clear(); char ch; ch = is.get(); while (ch != ' '&&ch != '\0') { str += ch; ch = is.get(); } return is; } }
說明一下:這個函數實現放在全局,是因為他的is要和對象str搶第一個位置,如果放在string類里面實現,那么第一個位置是this指針,也就是str對象,在用這個函數的時候就會很變扭。
ostream& operator<< (ostream& os, const string& str);
namespace cxy { class string { public: private: size_t _size; size_t _capacity; char* _str; }; ostream& operator<< (ostream& os, string& str) { for (auto ch:str) { os << ch; } return os; } }
istream& getline (istream& is, string& str)
獲取一行字符串
namespace cxy { class string { public: private: size_t _size; size_t _capacity; char* _str; }; istream&getline(istream&is ,string&s) { s.clear(); char ch; ch = is.get(); while (ch != '\0') { s += ch; ch = is.get(); } return is; } }
到此這篇關于 關于C++STL string類的介紹及模擬實現的文章就介紹到這了,更多相關C++STL string類介紹及模擬實現內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://blog.csdn.net/qq_53505979/article/details/118757127