STL容器之string類

文章目錄

  • STL容器之string類
    • 1、 什么是STL
    • 2、STL的六大組件
    • 3、string類
      • 3.1、string類介紹
      • 3.2、string類的常用接口說明
        • 3.2.1、string類對象的常見構造
        • 3.2.2、string類對象的容量操作
        • 3.2.3、string類對象的訪問及遍歷操作
        • 3.2.4、 string類對象的修改操作
        • 3.2.5、 string類非成員函數
      • 3.3、 vs和g++下string結構的說明
    • 4、string類的模擬實現

img

STL容器之string類

1、 什么是STL

C++標準模板庫(Standard Template Library,STL)是C++標準庫的一部分,提供了一組通用的模板類和函數,以實現常見的數據結構和算法


2、STL的六大組件

STL包含了多個模塊,其中一些主要的包括:

  1. 容器(Containers)

    • string:它被設計為一個動態數組,提供了一系列成員函數來操作字符串,同時自動處理內存的分配和釋放。

    • vector: 動態數組,可動態調整大小。

    • list: 雙向鏈表。

    • deque: 雙端隊列,支持在兩端高效地插入和刪除元素。

    • queue: 隊列。

    • stack: 棧。

    • set: 集合,不允許重復元素。

    • map: 映射,鍵-值對的關聯容器。

    • unordered_set 和 unordered_map: 使用哈希表實現的集合和映射。

  2. 算法(Algorithms)

  • 提供了許多常見的算法,如排序、搜索、遍歷等。
  • 包括了泛型算法,例如 sortfindbinary_search 等。
  1. 迭代器(Iterators)

    • 提供了多種迭代器類型,用于遍歷不同類型的數據結構。
  2. 函數對象(Function Objects)也稱仿函數(functor)

  • 包括了一些預定義的函數對象,如比較器等。
  1. 適配器(Adapters)

    • 提供了用于修改容器接口的適配器,如 stackqueue priority_queue(優先隊列,基于堆實現)。
  2. 空間配置器(allocator)

  • std::allocator: 是STL中默認的空間配置器。它使用 newdelete 運算符來進行內存分配和釋放。

3、string類

3.1、string類介紹

string類的文檔介紹

  1. 字符串是表示字符序列的類
  2. 標準的字符串類提供了對此類對象的支持,其接口類似于標準字符容器的接口,但添加了專門用于操作單字節字符/字符串的設計特性。
  3. string類是使用char(即作為它的字符類型,使用它的默認char_traits和分配器類型(關于模板的更多信息,請參閱basic_string)。
  4. string類是basic_string模板類的一個實例,它使用char來實例化basic_string模板類,并用char_traits和allocator作為basic_string的默認參數(根于更多的模板信息請參考basic_string)。
  5. 注意:這個類獨立于所使用的編碼來處理字節:如果用來處理多字節或變長字符(如UTF-8)的序列,這個類的所有成員(如長度或大小)以及它的迭代器,將仍然按照字節(而不是實際編碼的字符)來操作。

總結

  1. string是表示字符串的字符串類
  2. 該類的接口與常規容器的接口基本相同,再添加了一些專門用來操作string的常規操作
  3. string在底層實際是:basic_string模板類的別名,typedef basic_string<char, char_traits, allocator> string
  4. 不能操作多字節或者變長字符的序列

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

3.2、string類的常用接口說明

string類對象其實就是字符串,但是字符串不一定是string類對象

3.2.1、string類對象的常見構造
(constructor)函數名稱功能說明
string()(重點)構造空的string類對象,即空字符串
string (const string& str)(重點)拷貝構造函數
string (const string& str, size_t pos, size_t len = npos)構造從string類對象str的pos位置向后len長度的string類對象
string (const char s)(重點)*用C-string(字符串,不是字符串對象)來構造string類對象
string (const char s, size_t n)*構造字符串s從開始位置到n位置的string類對象
string (size_t n, char c)構造n個連續字符c的string類對象
int main() {//構造函數/拷貝構造函數string s1;cout << s1 << endl;string s2("hello");cout << s2 << endl;string s3(s2);cout << s3 << endl;string s4(s3, 2, 10);cout << s4 << endl;string s5("world", 2);cout << s5 << endl;return 0;
}
3.2.2、string類對象的容量操作
函數名稱功能說明
size(重點)返回string類對象有效字符長度
length返回string類對象有效字符長度
max_size返回string類對象可以達到的最大字符長度
resize(重點)將有效字符的個數改成n個,多出的空間用字符c填充(如果有參數字符c)
capacity返回當前已經分配給string類對象的存儲空間大小,單位是字節
reserve(重點)要求string類對象的容量調整為計劃好的容量(參數為n),如果n小于之前的容量,則不調整,大于則調整為n(看編譯器,有些編譯器可能大于n)
clear(重點)清空string類對象的內容,使其變成一個空字符串
empty(重點)判斷string類對象是不是空
int main() {string s1("hello world a");cout << s1.capacity() << endl;//返回當前已經分配給字符串的存儲空間大小,單位是字節cout << s1.size() << endl;//返回字符串有效字符長度cout << s1.length() << endl;//返回字符串有效字符長度cout << s1.max_size() << endl;//返回字符串可以達到的最大字符長度s1.resize(25, 'x');//將有效字符的個數該成n個,多出的空間用字符c填充(如果有參數字符c)cout << s1.size() << endl;cout << s1.capacity() << endl;s1.reserve(33);//要求字符串的容量調整為計劃好的容量(參數為n),如果n小于之前的容量,則不調整,大于則調整為n(看編譯器,有些編譯器可能大于n)cout << s1 << endl;cout << s1.capacity() << endl;s1.clear();//清空字符串的內容,使其變成一個空字符串cout << s1.empty() << endl;//判斷字符串是不是空return 0;
}

注意

  1. size()與length()方法底層實現原理完全相同,引入size()的原因是為了與其他容器的接口保持一致,一般情況下基本都是用size()
  2. clear()只是將string中有效字符清空,不改變底層空間大小
  3. resize(size_t n) 與 resize(size_t n, char c)都是將字符串中有效字符個數改變到n個,不同的是當字符個數增多時:resize(n)用0來填充多出的元素空間,resize(size_t n, char c)用字符c來填充多出的元素空間。注意:resize在改變元素個數時,如果是將元素個數增多,可能會改變底層容量的大小,如果是將元素個數減少,底層空間總大小不變既影響容量,也影響數據
  4. reserve(size_t res_arg=0):為string預留空間,不改變有效元素個數,當reserve的參數小于string的底層空間總大小時,reserver不會改變容量大小只影響容量,不影響數據
3.2.3、string類對象的訪問及遍歷操作
函數名稱功能說明
operator[](重點)返回string類對象在pos位置的字符引用,分const和非const,const則字符串內容(字符)不能被修改
at和opreator功能一樣
back取string類對象象的末尾字符
front取string類對象的最前面字符
begin返回一個迭代器指向string類對象最前面的字符,分const和非const,const是使得this指向的內容不能改變
end返回一個迭代器指向string類對象最后面的字符的后面一個位置,和begin一樣,分const和非const
rbegin反向迭代器,和begin差不多,就是這是指向string類對象最末尾字符位置
rend反向迭代器,和begin差不多,就是這是指向string類對象最前面字符的前一個位置
cbegin和begin差不多,但是這是專門用于const迭代器的
crbegin和cbegin差不多,就是這是指向string類對象最末尾字符位置
范圍forC++11支持更簡潔的范圍for的新遍歷方式
int main() {const string str1("hello ynu");string str2("hello ynu");//    str1[1] = '1';//常量string對象,這里調用的是const char& operator[] (size_t pos) const;str2[1] = 'n';str2.at(2) = 'y';char ch1 = str2.back();char ch2 = str2.front();string::iterator it2 = str2.begin();while (it2 != str2.end()) {cout << *it2;fflush(stdout);//將緩沖區數據刷新到終端it2++;}cout << endl;//const迭代器string::const_iterator it1 = str1.begin();while (it1 != str1.end()) {cout << *it1;it1++;}cout << endl;//反向迭代器string::reverse_iterator it3 = str2.rbegin();while (it3 != str2.rend()) {cout << *it3;it3++;}cout << endl;//專屬/const迭代器string::const_iterator it = str1.cbegin();while (it != str1.end()) {cout << *it;it++;}cout << endl;//范圍forfor (auto e: str2) {cout << e;}cout << endl;return 0;
}

3.2.4、 string類對象的修改操作
函數名稱功能說明
operator+=(重點)在string類對象末尾追加字符、字符串或者string類對象
append在string類對象末尾追加字符(參數需要加上添加字符的個數n)、字符串或者string類對象
push_back在string類對象末尾增加一個字符
npos(重點)大小為無符號數的最大值,用int表示即-1
insert在string類對象pos位置之前插入字符(參數需要加上添加字符的個數n)、字符串或者string類對象
erase從string類對象pos位置開始刪除長度為len的字符串,若不指定len,則len為npos(最大無符號int值)
replace從string類對象pos位置開始向后長度為len的字符串替換為新字符(參數需要加上添加字符的個數n)、新字符串或者新string類對象
swap用一個新string類對象交換本string類對象的內容。注意這里是引用,可以減少對象拷貝
c_str(重點)返回C格式字符串,這個比data常用
data和c_str一樣
copy將string類對象從pos位置開始向后的n個字符復制到新字符數組里,并返回這個復制的字符串長度
findstring類對象從pos位置開始向后查找字符、字符串或者string類對象,返回第一次出現的起始字符位置。pos不指定,則從string類對象的第一個字符開始查找。沒找到則返回npos
rfind和find差不多,這是pos位置從后往前找,找到返回返回第一次出現的起始字符位置。沒找到返回npos
find_first_of在string類對象中找到字符、字符串和string類對象里的匹配的任意字符的第一個位置
substr返回一個string類對象,這個string類對象是原string類對象從pos位置開始向后len長度的截取的字符串副本
int main() {string s1("hello world");string s2("no no no");//operator+=s2 += "hh";s2 += 'x';s2 += s1;//appends1.append(1, 'x');s1.append("hh");s1.append(s2);//push_backs2.push_back('x');//inserts1.insert(0, "xx");s1.insert(0, 2, 'x');//erases1.erase(0, 4);//replaces1.replace(0, 4, "x");//swaps1.swap(s2);//c_strconst char *str = s1.c_str();//dataconst char *str1 = s1.data();string s3("hello world");//copychar buffer[20] = {0};size_t length = s3.copy(buffer, 8, 0);buffer[length] = '\0';cout << buffer << endl;//findsize_t found1 = s3.find('d', 3);cout << found1 << endl;size_t found2 = s3.find('f');//測試是不是用int表示的-1int test = found2;cout << found2 << endl;cout << test << endl;//rfindsize_t found3 = s3.rfind("ll", 5);cout << found3 << endl;string s4("hello gun qnd world haha no --skas wcl cb ");//find_first_ofsize_t found4 = s4.find_first_of("gunwcqnd", 0);while (found4 != std::string::npos) {s4[found4] = '*';found4 = s4.find_first_of("gunwcqnd", found4 + 1);}cout << s4 << endl;//substrstring sub_str = s4.substr(0, 9);cout << sub_str << endl;return 0;
}

注意

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

  2. 對string操作時,如果能夠大概預估到放多少字符,可以先通過reserve把空間預留好。

3.2.5、 string類非成員函數
函數名稱功能說明
operator+返回一個string類對象,這是string類對象是(字符、字符串、string類對象)的其中兩個的串聯
relational operators(重點)包含操作符==、!=、<、<=、>、>=,返回值都是bool類型
swap交換兩個string類對象的值。這是非成員函數,還有一個成員函數swap
operator>>(重點)從輸入流中提取字符串,并存儲到string類對象str中,str中之前到數據將會被覆蓋。即輸入運算符重載
operator<<(重點)將string類對象str的字符序列插入到輸出流中。即即輸出運算符重載
getline(重點)獲取一行字符串。彌補了operator>>的缺陷(遇到第一個空格就只讀到第一個空格之前的字符串)
int main() {//operator+string s1("hello");string s2("world");string s3 = s1 + s2;cout << s3 << endl;string s4 = s1 + 'x';cout << s4 << endl;//operator==bool b = s1 == s2;cout << b << endl;//swapcout << s1 << endl;cout << s2 << endl;swap(s1, s2);cout << s1 << endl;cout << s2 << endl;//operator>>cin >> s1;cout << s1 << endl;//operator<<cout << s2 << endl;string s5("hello ynu");//getlinegetline(cin, s5);cout << s5 << endl;return 0;
}

3.3、 vs和g++下string結構的說明

注意:下述結構是在32位平臺下進行驗證,32位平臺下指針占4個字節。

  • vs下string的結構
    string總共占28個字節,內部結構稍微復雜一點,先是有一個聯合體,聯合體用來定義string中字符串的存儲空間:

    • 當字符串長度小于16時,使用內部固定的字符數組來存放

    • 當字符串長度大于等于16時,從堆上開辟空間

      union _Bxty
      { // storage for small buffer or pointer to larger onevalue_type _Buf[_BUF_SIZE];pointer _Ptr;char _Alias[_BUF_SIZE]; // to permit aliasing
      } _Bx;
      

      這種設計也是有一定道理的,大多數情況下字符串的長度都小于16,那string對象創建好之后,內部已經有了16個字符數組的固定空間,不需要通過堆創建,效率高。

      其次:還有一個size_t字段保存字符串長度,一個size_t字段保存從堆上開辟空間總的容量。

      最后:還有一個指針做一些其他事情。

      故總共占16+4+4+4=28個字節。

  • g++下string的結構
    g++下,string是通過寫時拷貝實現的,string對象總共占4個字節,內部只包含了一個指針,該指針將來指向一塊堆空間,內部包含了如下字段:

    • 空間總大小

    • 字符串有效長度

    • 引用計數

      struct _Rep_base
      {size_type _M_length;size_type _M_capacity;_Atomic_word _M_refcount;
      };
      

      指向堆空間的指針,用來存儲字符串。

  • CLion下string的結構

    CLion下string對象總共占12個字節,是在_rep里存儲了三個指針,分別是__l、__s、__r。因此總共12+4+4+4 = 24字節。


4、string類的模擬實現

  • main.cpp文件

    #include "string.h"int main() {
    //    xp::test_string1();
    //    xp::test_string2();
    //    xp::test_string3();
    //    xp::test_string4();
    //    xp::test_string5();
    //    xp::test_string6();
    //    xp::test_string7();
    //    xp::test_string8();
    //    xp::test_string9();
    //    xp::test_string10();
    //    xp::test_string11();xp::test_string12();return 0;
    }
  • string.cpp文件

    //
    // Created by 徐鵬 on 2023/11/29.
    //#include "string.h"namespace xp {string::string(const char *s) {_size = strlen(s);//這里還沒有size()呢,size()得自己寫_capacity = _size;_str = new char[_capacity + 1];//多開一個空間存\0strcpy(_str, s);}//拷貝構造函數 --   傳統寫法
    //    string::string(const string &str) {
    //        _size = str._size;
    //        _capacity = str._capacity;
    //        _str = new char[_capacity + 1];
    //        strcpy(_str, str._str);
    //    }//  現代寫法string::string(const string &str) : _str(nullptr), _size(0),_capacity(0) {//這里得使用初始化列表或者在private里得成員變量進行缺省,防止交換后tmp指向隨機值,調用析構就會出錯string tmp(str._str);swap(tmp);}void string::swap(string &str) {std::swap(_str, str._str);std::swap(_size, str._size);std::swap(_capacity, str._capacity);}void string::reserve(size_t n) {if (n > _capacity) {//擴容char *new_str = new char[n + 1];strcpy(new_str, _str);delete[] _str;_str = new_str;_capacity = n;}//小于等于則不改變容量}void string::resize(size_t n) {if (n > _capacity) {//需要重新開辟空間reserve(n);} else {//縮小容量和有效字符_capacity = n;_size = n;_str[n] = '\0';}}char &string::operator[](size_t pos) {assert(pos < _size);return _str[pos];}const char &string::operator[](size_t pos) const {assert(pos < _size);return _str[pos];}char &string::at(size_t pos) {
    //        assert(pos < _size);
    //        拋異常return _str[pos];}const char &string::at(size_t pos) const {
    //        assert(pos < _size);
    //        拋異常return _str[pos];}void string::append(const string &str) {size_t total_size = _size + str._size;//如果新插入的字符串加上之前的字符串的長度大于容量,則需要擴容if (total_size > _capacity) {reserve(total_size);}//把字符加進來for (int i = 0; i < str._size; ++i) {_str[_size++] = str[i];}_str[_size] = '\0';}void string::append(const char *s) {size_t total_size = _size + strlen(s);//如果新插入的字符串加上之前的字符串的長度大于容量,則需要擴容if (total_size > _capacity) {reserve(total_size);}//把字符加進來strcpy(_str + _size, s);_size += strlen(s);}string &string::operator+=(const string &str) {append(str);return *this;}string &string::operator+=(const char *s) {string str(s);append(str);return *this;}string &string::operator+=(char c) {push_back(c);return *this;}void string::push_back(char c) {size_t total_size = _size + 1;//如果新插入的字符加上之前的字符串的長度大于容量,則需要擴容if (total_size > _capacity) {reserve(total_size);}//把字符加進來_str[_size++] = c;_str[_size] = '\0';}string &string::insert(size_t pos, const string &str) {assert(pos < _size);
    //        size_t total_size = _size + str._size;
    //        //如果新插入的字符串加上之前的字符串的長度大于容量,則需要擴容
    //        if (total_size > _capacity) {
    //            reserve(total_size);
    //        }
    //        int end = _size;
    //        //pos后面數據先后移,每個元素后移str._size,這里end最后等于-1
    //        while (end >= (int) pos) {
    //            _str[end + str._size] = _str[end];
    //            --end;
    //        }
    //
            size_t end = total_size;
            //pos后面數據先后移,每個元素后移str._size,這里end最后等于0
            while (end > pos) {
                //當end減去str._size的時候,也就是預留的給插入的長度小于str._size時候,說明pos后面的數據移動完成,直接退出就行
                if (end - str._size < 0)
                    break;
                _str[end] = _str[end - str._size];
                --end;
            }
    //        //插入數據
    //        strncpy(_str + pos, str._str, str._size);
    //        _size = total_size;insert(pos, str.c_str());//復用return *this;}string &string::insert(size_t pos, const char *s) {assert(pos < _size);size_t total_size = _size + strlen(s);if (total_size > _capacity) {reserve(total_size);}size_t end = total_size;//pos后面數據先后移,每個元素后移str._size,這里是相當于元素后移,這里end最后等于0while (end > pos) {//當end減去strlen(str)的時候,也就是預留的給插入的長度小于strlen(str)時候,說明pos后面的數據移動完成,直接退出就行if (end - strlen(s) < 0)break;_str[end] = _str[end - strlen(s)];--end;}//插入數據strncpy(_str + pos, s, strlen(s));_size = total_size;return *this;}string &string::insert(size_t pos, size_t n, char c) {assert(pos < _size);size_t total_size = _size + n;if (total_size > _capacity) {reserve(total_size);}size_t end = total_size;//pos后面數據先后移,每個元素后移str._size,這里是相當于元素后移,這里end最后等于0while (end > pos) {if (end - n < 0)break;_str[end] = _str[end - n];--end;}//插入數據while (n--) {_str[pos++] = c;}_size = total_size;return *this;}string &string::erase(size_t pos, size_t len) {assert(pos < _size);if (len == std::string::npos || len + pos >= size()) {_str[pos] = '\0';//pos后面數據全部不要了_size = pos;} else {strcpy(_str + pos, _str + pos + len);_size -= len;}return *this;}size_t string::find(const string &str, size_t pos) const {assert(pos < _size);const char *ret = strstr(_str + pos, str._str);if (nullptr == ret) return std::string::npos;return ret - _str;}size_t string::find(const char *s, size_t pos) const {assert(pos < _size);const char *ret = strstr(_str + pos, s);if (nullptr == ret) return std::string::npos;return ret - _str;}size_t string::find(char c, size_t pos) const {assert(pos < _size);while (pos < _size) {if (_str[pos] == c) return pos;pos++;}//沒找到return std::string::npos;}string string::substr(size_t pos, size_t len) const {assert(pos < _size);size_t end = pos + len;if (len == npos || end >= _size) {end = _size;}string str;str.reserve(end - pos);//開辟空間while (pos < end) {str += _str[pos++];}//把\0也帶進去str._str[_size] = '\0';return str;}// 傳統寫法
    //    string &string::operator=(const string &str) {
    //        if (this != &str) {
    //            reserve(str._capacity);
    //            strcpy(_str, str._str);
    //            _size = str._size;
    //        }
    //
    //        return *this;
    //    }//  現代寫法string &string::operator=(string str) {//這里不會改變賦值的值,這里str只是臨時拷貝swap(str);return *this;}string &string::operator=(const char *s) {reserve(strlen(s));strcpy(_str, s);_size = strlen(s);return *this;}string &string::operator=(char c) {reserve(1);_str[0] = c;_str[1] = '\0';_size = 1;return *this;}ostream &operator<<(ostream &out, string &str) {for (auto e: str) {out << e;}return out;}istream &operator>>(istream &in, string &str) {str.clear();char buffer[128];//緩沖一下char c = in.get();int i = 0;while (c != ' ' && c != '\n') {buffer[i++] = c;if (i == 127) {buffer[i] = '\0';str += buffer;i = 0;//重置}c = in.get();}//提前讀到' ' 或者 '\n'if (i > 0) {buffer[i] = '\0';str += buffer;}return in;}string::~string() {delete[] _str;_str = nullptr;_capacity = 0;_size = 0;}void test_string1() {string s1;cout << s1.c_str() << endl;string s2("hello world");cout << s2.c_str() << endl;string s3(s2);cout << s3.c_str() << endl;}void test_string2() {string s1;string s2("hello world");cout << s2.capacity() << endl;s2.reserve(2);cout << s2.capacity() << endl;s2.resize(15);cout << s2.capacity() << endl;s2.resize(7);cout << s2.capacity() << endl;cout << s2.c_str() << endl;}void test_string3() {string s1("hello world");const string s2("nihao liangzai");string::iterator it1 = s1.begin();while (it1 != s1.end()) {cout << *it1 << " ";++it1;}cout << endl;string::const_iterator it2 = s2.begin();while (it2 != s2.end()) {cout << *it2 << " ";++it2;}cout << endl;}void test_string4() {string s1("hello world");const string s2("nihao liangzai");//        s1.append(s2);
    //        s1.append("hh");
    //        s1 += s2;
    //        s1 += "hh";
    //        s1 += 'x';s1.push_back('v');cout << s1.c_str() << endl;}void test_string5() {string s1("hello world");const string s2("nihao liangzai");//        s1.insert(0, s2);
    //        s1.insert(2, "hh");s1.insert(11, 5, 'x');cout << s1.c_str() << endl;}void test_string6() {string s1("hello world");const string s2("nihao liangzai");s1.erase();cout << s1.c_str() << endl;}void test_string7() {string s1("hello world");string s2("nihao liangzai");cout << s1.c_str() << endl;cout << s2.c_str() << endl;s1.swap(s2);cout << s1.c_str() << endl;cout << s2.c_str() << endl;}void test_string8() {string s1("hello world");const string s2("wo");size_t pos1 = s1.find(s2);size_t pos2 = s1.find("d");size_t pos3 = s1.find("f");size_t pos4 = s1.find('o');cout << pos1 << endl;cout << pos2 << endl;cout << (int) pos3 << endl;cout << (int) pos4 << endl;}void test_string9() {string s1("hello world");string s2(s1.substr(5, 2));const string s3("nihao liangzai");string s4(s3.substr(2, 5));cout << s2.c_str() << endl;cout << s4.c_str() << endl;}void test_string10() {string s1("hello world");const string s2("nihao liangzai");cout << s1.c_str() << endl;s1 = s2;cout << s1.c_str() << endl;s1 = "woshixp";cout << s1.c_str() << endl;s1 = '1';cout << s1.c_str() << endl;}void test_string11() {string s;cin >> s;cout << s << endl;}void test_string12() {string s1("111");string s2(s1);cout << s1 << endl;cout << s2 << endl;string s3;s3 = s2;cout << s3 << endl;}}
    
  • string.h文件

    //
    // Created by 徐鵬 on 2023/11/29.
    //#include <cstring>
    #include <iostream>
    #include <assert.h>
    #include <vector>using namespace std;#ifndef DEMO_42_STRING_H
    #define DEMO_42_STRING_H#endif  DEMO_42_STRING_Hnamespace xp {class string {public://構造函數string() : _str(new char[1]), _size(0), _capacity(0) {_str[0] = '\0';//空字符串也包含一個\0}string(const char *s);//拷貝構造函數string(const string &str);//字符串大小size_t size() const {return _size;}//總容量size_t capacity() const {return _capacity;}//string轉char*const char *c_str() const {return _str;}//要求string類對象的容量調整為計劃好的容量void reserve(size_t n);//將有效字符的個數改成n個void resize(size_t n);//清空字符串void clear() {_str[0] = '\0';_size = 0;//只清空數據,不清空容量}//判斷字符串是不是空字符串bool empty() {return _size == 0;}//下標訪問char &operator[](size_t pos);const char &operator[](size_t pos) const;char &at(size_t pos);const char &at(size_t pos) const;const char &back() const {return _str[_size - 1];}const char &front() const {return _str[0];}//迭代器typedef char *iterator;typedef const char *const_iterator;iterator begin() {return _str;}iterator end() {return _str + _size;}const_iterator begin() const {return _str;}const_iterator end() const {return _str + _size;}//尾插字符或者字符串void append(const string &str);void append(const char *s);//尾插字符或者字符串string &operator+=(const string &str);string &operator+=(const char *s);string &operator+=(char c);//尾插字符void push_back(char c);//從某個位置前插字符string &insert(size_t pos, const string &str);string &insert(size_t pos, const char *s);string &insert(size_t pos, size_t n, char c);//從某個位置向后刪除n個字符string &erase(size_t pos = 0, size_t len = std::string::npos);//交換void swap(string &str);//從某個位置開始查找字符、字符串、string對象位置size_t find(const string &str, size_t pos = 0) const;size_t find(const char *s, size_t pos = 0) const;size_t find(char c, size_t pos = 0) const;//取子串string substr(size_t pos = 0, size_t len = npos) const;//賦值string &operator=(string str);string &operator=(const char *s);string &operator=(char c);~string();private:char *_str;size_t _capacity;size_t _size;static const size_t npos = -1;};//重載流插入ostream &operator<<(ostream &out, string &str);//重載流提取istream &operator>>(istream &in, string &str);void test_string1();void test_string2();void test_string3();void test_string4();void test_string5();void test_string6();void test_string7();void test_string8();void test_string9();void test_string10();void test_string11();void test_string12();}
    

OKOK,C++ STL容器之string類就到這里。如果你對Linux和C++也感興趣的話,可以看看我的主頁哦。下面是我的github主頁,里面記錄了我的學習代碼和leetcode的一些題的題解,有興趣的可以看看。

Xpccccc的github主頁

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/714251.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/714251.shtml
英文地址,請注明出處:http://en.pswp.cn/news/714251.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

車輛維護和燃油里程跟蹤器LubeLogger

什么是 LubeLogger &#xff1f; LubeLogger 是一個自托管、開源、基于網絡的車輛維護和燃油里程跟蹤器。 LubeLogger 比較適合用來跟蹤管理您的汽車的維修、保養、加油的歷史記錄&#xff0c;比用 Excel 強多了 官方提供了在線試用&#xff0c;可以使用用戶名 test 和密碼 123…

oracle-long類型轉clob類型及clob類型字段的導出導入

1、若oracle數據庫表字段類型有long類型&#xff0c;有時候我們需要模糊匹配long類型字段時&#xff0c;是查詢不出來結果的&#xff0c;此時使用TO_LOB&#xff0c;將long類型轉成clob類型&#xff0c;就可以模糊匹配信息。 例如&#xff1a;oracle數據庫查詢所有視圖內容中包…

機器學習-4

文章目錄 前言數組創建切片索引索引遍歷切片編程練習 總結 前言 本篇將介紹數據處理 Numpy 庫的一些基本使用技巧&#xff0c;主要內容包括 Numpy 數組的創建、切片與索引、基本運算、堆疊等等。 數組創建 在 Python 中創建數組有許多的方法&#xff0c;這里我們使用 Numpy 中…

機器學習-5

文章目錄 前言Numpy庫四則運算編程練習 前言 本片將介紹Numpy庫中的四則運算。 Numpy庫四則運算 Numpy庫可以直接進行一些四則運算&#xff0c;快速的處理兩個Numpy數組&#xff1a; a np.array([[1,2,3],[4,5,6]]) b np.array([[4,5,6],[1,2,3]])向量與向量之間 1.加法 …

14.最長公共前綴

題目&#xff1a;編寫一個函數來查找字符串數組中的最長公共前綴。 如果不存在公共前綴&#xff0c;返回空字符串""。 解題思路&#xff1a;橫向掃描&#xff0c;依次遍歷每個字符串&#xff0c;更新最長公共前綴。另一種方法是縱向掃描。縱向掃描時&#xff0c;從前…

基于tomcat的JavaWeb實現

Tomcat服務器 免費&#xff0c;性能一般的服務器 安裝配置 基于Java&#xff0c;故需要配置環境變量&#xff0c;新加系統路徑JAVA_HOME&#xff0c;路徑為jdk的主目錄。 而后打開bin目錄下的startup.bat文件出現如下窗口說明配置成功 idea繼承tomcat服務器 使用java開發…

Linux 之壓縮與解壓相關命令的基礎用法

目錄 1、zip 與 unzip 2、gzip 命令 3、tar 命令 1、zip 與 unzip 在桌面新建一個文件和文件夾用于測試 在 test 目錄下有一個 1.txt 文件 我們使用 zip 命令對其壓縮 用法&#xff1a; zip 自定義壓縮包名 被壓縮文件路徑位置 zip myon.zip 1.txt 因為我們這里就是在 …

linux_day04

大綱&#xff1a;命令&#xff0c;vim&#xff0c;gcc&#xff0c;編譯工具&#xff0c;生成代碼&#xff0c;調試&#xff0c;庫makefile&#xff0c;系統編程 文件系統&#xff1a;文件屬性&#xff0c;文件內容&#xff0c;萬物皆文件&#xff08;不在內存中的是文件&#…

ProtoBuf 是什么?

1. 序列化概念 序列化和反序列化 序列化&#xff1a;把對象轉換為字節序列的過程稱為對象的序列化。 反序列化&#xff1a;把字節序列恢復為對象的過程稱為對象的反序列化。 什么情況下需要序列化 存儲數據&#xff1a;當你想把的內存中的對象狀態保存到?個?件中或者存到數…

怎么壓縮成mp4視頻?

在數字化時代&#xff0c;視頻已經成為我們日常生活中不可或缺的一部分。然而&#xff0c;有時候我們可能會遇到視頻文件太大的問題&#xff0c;不便于傳輸、存儲或分享。那么&#xff0c;如何將視頻壓縮成MP4格式&#xff0c;以減小文件大小呢&#xff1f;本文將為您介紹幾種簡…

docker學習第一步:基于Linux安裝docker!

要求Linux下的CentOS 7.0 以上的版本 01、安裝docker版本倉庫 1、設置倉庫 sudo yum install -y yum-utils device-mapper-persistent-data lvm2 2、穩定倉庫 sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo 現在我也找了很…

醫學大數據|文獻閱讀|有關“胃癌+機器學習”的研究記錄

目錄 1.基于32基因特征構建的機器學習模型可有效預測胃癌患者的預后和治療反應 2.胃癌患者術后90天死亡率的機器學習風險預測模型 3.使用機器學習模型預測幽門螺桿菌根除患者胃癌患病風險 4.利用初始內窺鏡檢查和組織學結果進行個性化胃癌發病率預測 1.基于32基因特征構建的…

隨想錄算法訓練營第四十八天|121. 買賣股票的最佳時機、122.買賣股票的最佳時機II

121. 買賣股票的最佳時機 public class Solution {public int MaxProfit(int[] prices) {int result0;int lowint.MaxValue;for(int i0;i<prices.Length;i){if(prices[i]<low){lowprices[i];}else{resultMath.Max(result,prices[i]-low);}}return result;} } 先遍歷找到…

機器學習_10、集成學習-AdaBoost

AdaBoost AdaBoost&#xff08;Adaptive Boosting的簡稱&#xff09;是一種集成學習方法&#xff0c;它的核心思想在于將多個弱學習器組合起來&#xff0c;形成一個強學習器。通過這種方式&#xff0c;AdaBoost能夠顯著提高分類性能。下面詳細介紹AdaBoost的主要概念和工作原理…

查看網絡連接的netstat

netstat是一個監控TCP/IP網絡的非常有用的工具&#xff0c;可以顯示路由表、實際的網絡連接&#xff0c;以及每一個網絡接口設備的狀態信息&#xff0c;可以讓用戶得知目前都有哪些網絡連接正在運作。netstat用戶顯示與IP、TCP、UDP和ICMP協議相關的統計數據&#xff0c;一般用…

【Vue3】PostCss 適配

px 固定的單位&#xff0c;不會進行自適應。rem r root font-size16px 1rem16px&#xff0c;但是需要手動進行單位的換算vw vh 相對于視口的尺寸&#xff0c;不同于百分比&#xff08;相對于父元素的尺寸&#xff09;375屏幕 1vw 3.75px 利用插件進行 px&#xff08;設計稿&…

算法復習之二分【備戰藍橋杯】

二分模板一共有兩個&#xff0c;分別適用于不同情況。 算法思路&#xff1a;假設目標值在閉區間[l, r]中&#xff0c; 每次將區間長度縮小一半&#xff0c;當l r時&#xff0c;我們就找到了目標值。 版本一 當我們將區間[l, r]劃分成[l, mid]和[mid 1, r]時&#xff0c;其更…

Docker自定義JDK鏡像并拉取至阿里云鏡像倉庫全攻略

前言 隨著容器技術的日益成熟&#xff0c;Docker已經成為現代軟件開發和部署的標配工具。其中&#xff0c;自定義Docker鏡像是滿足特定項目需求的關鍵步驟。特別是在Java開發環境中&#xff0c;我們可能需要為不同的項目配置不同版本的JDK。這時&#xff0c;通過Docker自定義J…

臨時筆記2

臨時筆記2 數據庫設計 有哪些表 表里有哪些字段 表和表之間是什么關系 JDBC(全稱&#xff1a;JAVA DATABASE CONNECTIVITY) 本質是官方定義的一套操作所有關系型數據庫的規則&#xff0c;即接口。每個數據庫廠商去實現這一接口&#xff0c;寫出實現類&#xff0c;即驅動&…

List<Object>集合對象屬性拷貝工具類

目錄 問題現象&#xff1a; 問題分析&#xff1a; 解決方法&#xff1a; 問題現象&#xff1a; 最近在項目中經常會使用到BeanUtils工具類來作對象的屬性字段拷貝&#xff0c;但如果應用到List集合的話就需要遍歷去操作了&#xff0c;如下&#xff1a; 打印結果&#xff1a; …