【C++】string類--常見接口及其模擬實現

目錄

1. 遍歷

1.1. 下標+operator[ ]

1.2. c_str

1.3. 迭代器

1.4. 范圍for

2. 增

2.1. push_back

2.2. 重載+=(char ch)

2.3. appand

2.4. 重載+=(char* ch)

2.5. insert(任意位置插入)

2.5.1. 任意位置插入一個字符

2.5.2. 任意位置插入一個字符串

3. 刪

3.1. earse

情況一:len==npos說明要全部刪除完

情況二:并不全部刪除完

4. 查

4.1. 查找一個字符

4.2. 查找一個字符串

4.3. 字符串比較

5. 改

5.1. reserve

5.2. resize

情況一:resize的n大于當前字符串空間長度(注意是空間長度)

情況二:resize的n小于_capacity,但是大于_size

情況三:resize的n小于當前字符串長度


上一篇文章我們講解了string類的構造、拷貝構造、賦值及其模擬實現
下面是我們本篇文章的主要內容:

1. 遍歷

1.1. 下標+operator[ ]

char& operator[](size_t pos)
{assert(pos < strlen(_str));return _str[pos];
}const char& operator[](size_t pos) const 
{assert(pos < strlen(_str));return _str[pos];
}int main()
{string s1("hello world");for (int i = 0; i < s1.size(); ++i){cout << s1[i];}return 0;
}


1.2. c_str

也就是說c_str返回的值指向該字符串并且包含“\0”的字符序列,使用c_str( )來打印字符串,當碰到“\0”時就停止(這是因為C/C++中字符串處理函數(如printf,?cout,?strcpy等)都遵循一個約定:將以null字符('\0')作為字符串的結束標志)。

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


1.3. 迭代器

迭代器:string的迭代器的底層其實就是一個char*的原生指針,所以使用string迭代器只需要像使用普通指針一樣即可。但是其他容器的底層不應該否是原生指針。

typedef char* iterator;
typedef const char* const_iterator;
iterator begin()
{return _str;
}iterator begin() const
{return _str;
}
iterator end()
{return _str + _size;
}iterator end() const
{return _str + _size;
}

然后我們使用迭代器來進行字符串的遍歷:

int main()
{s::string s1("Hello World");s::string::iterator it = s1.begin();while (it != s1.end()){cout << *it << "";it++;}
}

PS:這個地方要注意的是要注意使用的是C++string類中的迭代器還是我們自定義類string中的迭代器。


1.4. 范圍for

for的使用:

for (auto e : s1)
{cout << e << " ";
}

其實范圍for的底層機制同樣是一個迭代器,我們可以通過下面的方式進行驗證,我們將迭代器給注釋掉,我們來看一下發生什么:


2. 增

2.1. push_back

可以看到,push_back的作用是將一個字符添加到原有字符串后面,具體步驟:

  • 我們先要判斷時候需要擴容:如果size==capacity,說明滿了。擴容:開辟一個兩倍內存的新空間,然后原有字符串拷貝至新空間,釋放原空間
  • 添加的新字符應該放在size的位置
  • 然后處理“\0”即可

2.2. 重載+=(char ch)

但是我們在日常寫代碼中并不會經常使用push_back,而是使用 += ,所以我們來重載一下 += ,它的實現中也可以服用push_back:

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

2.3. appand

這里可以注意到,前面兩個接口都是將單個字符添加到已有字符串結尾,而這個接口是將一個字符串添加到原來的字符串,步驟如下:

  • 首先需要考慮要不要擴容,而且這里的擴容不能只是簡單地將空間變為兩倍,因為這樣并不能保證空間足夠。應該是將原字符串長度和新添加字符串長度相加,這樣得到的空間就一定能滿足要求,這里我們使用reserve函數(見下面的5.1)
  • 然后更新 _size
		void append(const char* str){size_t len = _size + strlen(str);if (len > _capacity){reserve(len);}strcpy(_str + _size, str);_size = len;//insert(_size, str);}

2.4. 重載+=(char* ch)

與單個字符的重載復用push_back一樣,復用appand接口:

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

2.5. insert(任意位置插入)

2.5.1. 任意位置插入一個字符

  • 首先判斷pos位置是否合法
  • 然后判斷是否需要擴容
  • 然后從結尾的"\0"開始,從后往前一次向后移動一位,到pos為止
  • 插入新字符,然后更新_size

string& insert(size_t pos, char ch)
{assert(pos <= _size);if (_capacity == _size){reserve(_capacity == 0 ? 4 : _capacity * 2);}size_t end = _size + 1;while (end > pos){_str[end - 1] = _str[end];--end;}_str[pos] = ch;++_size;return *this;
}

2.5.2. 任意位置插入一個字符串

  • 插入位置是否合法
  • 判斷是否需要擴容,這里需要擴大到原字符串長度+插入字符串長度
  • 將原字符串包括pos在內的后面所有字符(包括"\0")往后移動len=strlen(ch)位
  • 然后將新字符串插入,然后更新_size

		string& insert(size_t pos, const char* str){assert(pos <= _size);size_t len = strlen(str);if (len == 0){return *this;}if (_size + len > _capacity){reserve(_size + len);}//挪動數據size_t end = _size + len;//while(end >= end+len)while (end > pos+len-1){_str[end] = _str[end-len];--end;}//插入數據  size_t i = 0;while (i < len){_str[pos+i] = str[i];++i;}_size += len;return *this;}

3. 刪

3.1. earse

我們看這里提到了一個參數npos:

所以可以知道,earse的作用就是從pos開始,往后len個長度,把這些字符刪去。

情況一:len==npos說明要全部刪除完

那其實我們邏輯上刪除它只需要將pos位置賦值"\0"即可:

情況二:并不全部刪除完

首先找到需要刪除的子字符串的后一位,將其定為begin,然后我們需要做的就是將begin后面的所有字符全部往前移動,覆蓋掉需要刪除的字符:

string& earse(size_t pos, size_t len = std::string::npos)
{assert(pos < _size);if (len == std::string::npos || len + pos >= _size){_str[pos] = '\0';_size = pos;return *this;}else{size_t begin = pos + len;while (begin <= _size){_str[begin - len] = _str[begin];++begin;}_size -= len;return *this;}
}

4. 查

4.1. 查找一個字符

find查找字符串,返回查到的第一個滿足的字符:

size_t find(char ch, size_t pos = 0)
{for (; pos < _size; ++pos){if (_str[pos] == ch){return pos;}}return std::string::npos;
}

4.2. 查找一個字符串

size_t find(const char* ch, size_t pos)
{const char* p = strstr(_str + pos, ch);if (nullptr == p){return std::string::npos;}else{return p - _str;}
}

4.3. 字符串比較

bool operator < (const string& s)
{return strcmp(this->c_str(), s.c_str()) < 0;
}
bool operator == (const s::string& s)
{return strcmp(this->c_str(), s.c_str()) == 0;
}
bool operator<=(const string& s)
{return *this < s || *this == s;
}
bool operator>(const string& s)
{return !(*this <= s);
}
bool operator>=(const string& s)
{return !(*this < s);
}
bool operator!=(const string& s)
{return !(*this == s);
}

對于這段代碼有疑問的可以看下【C++】類和對象--類中6個默認成員函數(2) --運算符重載,這里涉及到成員函數隱藏this指針的問題。


5. 改

5.1. reserve

reserve的作用就是是個string的容量變成n:

  • 如果n小于等于_capacity,則不進行擴容
  • 否則開辟一個容量為n的char*,然后進行拷貝,注意釋放掉原有的內存
void reserve(size_t n)
{if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}
}

5.2. resize

resize是將字符串大小修改為n。

resize和reserve的區別是:reserve只對空間進行處理,但是resize不僅對空間進行影響,而且會改變_size的值。

情況一:resize的n大于當前字符串空間長度(注意是空間長度)

看下面這個例子,假設空間長度為15,字符串長度為11:

也就是擴容了之后會使用字符串參數填充滿:

情況二:resize的n小于_capacity,但是大于_size

這種情況下不需要擴容,所以_capacity不會變:

情況三:resize的n小于當前字符串長度

這個時候只會保存原字符串的前n個字符:

代碼如下:

//擴空間+初始化
//刪除部分數據,保留前n個
void resize(size_t n, char ch = '\0')
{if (n < _size){_size = n;_str[_size] = '\0';}else{if (n > _capacity){reserve(n);}for (size_t i = _size; i < n; ++i){_str[i] = ch;}_size = n;_str[_size] = '\0';}}

(本篇完)

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

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

相關文章

SCADA 云化部署核心:WebSocket 協議實現毫秒級遠程控制

在浙江某智慧水廠的中控室里&#xff0c;曾發生過一次驚險的遠程控制失誤&#xff1a;運維人員通過傳統 SCADA 系統&#xff08;工業控制系統的 “大腦”&#xff09;遠程調節水泵轉速&#xff0c;指令發出后&#xff0c;屏幕上卻遲遲沒有反饋 —— 等水泵轉速最終變化時&#…

大數據電商流量分析項目實戰:Day1-2 補充 軟件安裝和Zookeeper

?博客主頁&#xff1a; https://blog.csdn.net/m0_63815035?typeblog &#x1f497;《博客內容》&#xff1a;大數據、Java、測試開發、Python、Android、Go、Node、Android前端小程序等相關領域知識 &#x1f4e2;博客專欄&#xff1a; https://blog.csdn.net/m0_63815035/…

EMC電磁兼容進階3講培訓:專題三 近場探頭和頻譜儀在EMC整改中的應用

一節課&#xff0c;名企實戰型工程師讓你了解近場探頭與頻譜分析儀在EMC整改中的應用&#xff0c;從實際整改測試出發&#xff0c;結合實際項目案例進行講解。一頓聚餐的費用&#xff0c;助您入門一個很有前景的行業&#xff01; 注&#xff1a;不是賣資料&#xff01;不是賣資…

使用動態IP 需要注意什么

網絡安全防護動態IP會頻繁變更&#xff0c;需確保防火墻和殺毒軟件實時更新&#xff0c;防止因IP變動導致的安全漏洞。避免在公共網絡環境下登錄敏感賬戶&#xff0c;建議使用VPN加密連接。服務穩定性管理某些在線服務&#xff08;如遠程辦公、游戲服務器&#xff09;可能因IP變…

GitHub自動化利器:Probot框架實戰指南

引言 在當今快節奏的軟件開發世界中&#xff0c;自動化已成為提高生產力和保證代碼質量的關鍵要素。GitHub作為全球最大的代碼托管平臺&#xff0c;其豐富的API生態系統為自動化提供了無限可能。Probot作為一個基于Node.js的開源框架&#xff0c;專門用于構建GitHub應用程序&a…

第十四屆藍橋杯青少組C++選拔賽[2023.2.12]第二部分編程題(4、最大空白區)

參考程序1&#xff1a;#include <bits/stdc.h> using namespace std;int main() {int N, M;cin >> N >> M;vector<vector<int>> grid(N, vector<int>(M));for (int i 0; i < N; i)for (int j 0; j < M; j)cin >> grid[i][j]…

文心一言-Agent崗三輪面試全記錄

面經分享&#xff5c;文心一言-Agent崗三輪面試全記錄 前段時間面試了 文心一言團隊 - 大模型 Agent 崗&#xff0c;三輪面試下來感觸頗多。整體來說&#xff0c;文心團隊的面試節奏偏“循序漸進”&#xff1a;一面看基礎&#xff0c;二面看綜合素養&#xff0c;三面看思考深度…

【大前端++】幾大特征

大綱 大前端業務模型結構如下&#xff1a; 服務后臺大前端原生系統可定制的終端硬件 1、業務的起點技術結構基于跨平臺前端框架 Electronvue/Rect/其他web框架js/ts FlutterDartvue/Rect/其他web框架js/ts 其他前端框架結構 2、有特定的業務使用場景 人臉識別考勤 數字…

計算機網絡---網絡體系結構

文章目錄1. 網絡的概念1.1 什么是計算機網絡1.2 簡單的計算機網絡1.3 互聯網&#xff08;或因特網&#xff0c;Internet&#xff09;1.4 計算機網絡、互連網和互聯網三者的區別1.5 總結2. 網絡的組成、功能2.1 組成2.1.1 從組成部分看2.1.2 從工作方式看2.1.3 從邏輯功能看2.2 …

機器學習超參數調優全方法介紹指南

本篇文章Master Hyperparameter Tuning in Machine Learning適合希望深入了解超參數調優的讀者。文章的亮點在于介紹了多種調優方法&#xff0c;如手動搜索、網格搜索、隨機搜索、貝葉斯優化和元啟發式算法&#xff0c;并通過實際案例展示了這些方法在復雜模型&#xff08;如CN…

怎么降低 AIGC 生成率?

怎么降低 AIGC 生成率&#xff1f;市面上那些號稱 "AI 降重神器" 的工具真的有用嗎&#xff1f;想和大家聊聊我的看法 ——人工修改生成內容&#xff0c;可能是目前最靠譜的辦法。一、AI 降重工具的實際效果現在很多工具說能通過 AI 降低 AIGC 生成率&#xff0c;原理…

心磁圖 QRS 參數在 Brugada 綜合征心律失常風險分層中的應用

研究背景Brugada 綜合征是一種與致命性室性心律失常及心源性猝死風險相關的遺傳性心臟離子通道病&#xff0c;其典型特征為右胸導聯&#xff08;V1-V3&#xff09;出現特征性ST段抬高&#xff08;1型、2型或3型 Brugada 心電圖表現&#xff09;。然而&#xff0c;靜息心電圖呈現…

Futuring robot旗下家庭機器人F1將于2025年面世

2025年9月10日&#xff0c;張翼二次創業的機器人公司Futuring Robot發布了第一款家庭服務機器人F1。這款F1機器人不僅具備端茶送水、物品遞送、家庭整理等日常服務能力&#xff0c;還深度融合了多項教育輔助功能&#xff0c;如學習陪伴、棋類對弈、作業進度管理等&#xff0c;旨…

User類CRUD實現

代碼&#xff1a; WYend/Myblog_springbook3: 我的第一個個人網站&#xff08;后端版&#xff09; 隨時更新 一、數據庫的構建 交給ai 二、各類注解 Lombok注解 Data&#xff1a; 自動生成類的getter、setter、toString()、equals()、hashCode()方法適用于實體類&#xff…

【Linux | 網絡】數據鏈路層

一、以太網1.1 認識以太網1.2 以太網幀格式1.3 MAC地址1.3.1 認識MAC地址1.3.2 MAC地址的類型1.3.3 MAC地址 VS IP地址1.4 局域網如何通信1.5 局域網數據碰撞1.5.1 數據碰撞1.5.2 劃分碰撞域&#xff08;交換機&#xff09;二、ARP協議2.1 ARP協議的作用2.2 ARP數據報的格式2.3…

Google Ads廣告驗證全攻略:如何借助動態住宅IP精準投放?

在競爭激烈的數字廣告領域&#xff0c;Google Ads扮演著至關重要的角色。然而&#xff0c;隨著廣告政策的不斷更新和平臺對廣告質量要求的提高&#xff0c;廣告驗證已成為許多廣告主繞不開的環節。同時&#xff0c;如何實現精準投放&#xff0c;將廣告觸達最相關的目標受眾&…

鴻蒙Next Web組件生命周期詳解:從加載到銷毀的全流程掌控

想要精通鴻蒙應用開發&#xff1f;Web組件的9大生命周期回調是你必須掌握的上帝視角&#xff01;在鴻蒙應用開發中&#xff0c;Web組件是我們加載本地或在線網頁的強大工具。它提供了完整的生命周期回調體系&#xff0c;讓開發者能夠精準感知網頁加載的每個階段&#xff0c;從而…

python學習進階之異常和文件操作(三)

文章目錄1.程序異常2.文件操作3.json操作1.程序異常 1.1 異常 異常概念&#xff1a; 程序在運行時, 如果Python解釋器遇到到一個錯誤, 則會停止程序的執行, 并且提示一些錯誤信息, 這就是異常 拋出異常&#xff1a; 程序停止執行并且提示錯誤信息這個動作, 通常稱之為拋出(ra…

NodeJS 8 ,從 0 到 1:npm 包發布與更新全流程指南( 含多場景適配與踩坑總結 )

目錄 前言 一、準備工作 1.1 開發環境搭建 1.1.1 環境安裝 1.1.2 配置問題 1.2 賬號注冊 1.2.1 賬號注冊&#xff08;兩種方式&#xff09; 1.2.2 登錄驗證 1.2.3 個人設置 1.2.4 安全配置 1.3 初始配置 1.3.1 初始項目目錄 1.3.2 關鍵字段詳解 1.3.3 手動完善 二…

BERT中文預訓練模型介紹

bert-base-chinese 是由谷歌基于 BERT&#xff08;Bidirectional Encoder Representations from Transformers&#xff09;模型預訓練得到的適用于中文任務的模型版本。以下從多個方面對其進行詳細解釋&#xff1a; 模型概述 BERT 是一種基于 Transformer 架構的預訓練語言模型…