網站首頁 編程語言 正文
一、string類簡介
標準庫類型string
表示可變長的字符序列,使用string類型必須首先包含string頭文件。作為標準庫的一部分,string定義在命名空間std
中。
二、模擬實現
成員變量
?? ?char* _str; ?? ?size_t _size; ?? ?size_t _capacity;?? ?//不包含最后做標識的'\0' ?? ?static const size_t npos;
_str
用來存儲字符串,_size表示字符串有效數據個數,_capacity表示容量大小,其中不包含最后做標識的‘\0’
。
例如這樣一段代碼:string str(“hello”);
npos
是一個靜態成員常量,值為-1,因為size_t是無符號整數類型,所以它表示size_t類型的最大值。
當npos用在做成員函數中len的參數時,表示“直到字符串的結尾”,
例如用來刪除字符串中某一部分的函數erase(size_t pos = 0, size_t len = npos)
,如果沒傳參數len,那么就會從pos位置直接刪到最后。
當作為返回值時,npos通常表示不匹配,例如find函數返回npos,就意味著沒找到。
初始化string對象常用的幾種方式:
?? ?string s1("hello");?? ??? ? //默認初始化,s1是一個空字符串 ?? ?string s2 = s1; ? ? ? ? ?//s2是s1的副本 ?? ?string s3 = "hello"; ?? ?string s4(5, 'c'); ? ? ? //s4的內容是ccccc
成員函數
構造函數:
?string(const char* str = "") ?? ??? ?:_size(strlen(str)) ?? ??? ?,_capacity(_size) ?? ?{ ?? ??? ?_str = new char[_capacity + 1]; ?? ??? ?strcpy(_str, str); ?? ?}
這里需要注意的是參數列表的初始化順序與初始化列表列出的順序無關,只與它在類中聲明順序有關,由于我們聲明成員變量順序_size
在_capacity
前面,所以這里_size也要在_capacity前面。
容量_capacity
中不包含’\0’,所以申請空間時多申請一位。
重載一個用來初始化s4的構造函數
?string(const size_t n, const char ch) ?? ??? ?:_size(n) ?? ??? ?, _capacity(_size) ?? ?{ ?? ??? ?_str = new char[_capacity + 1]; ?? ??? ?for (size_t i = 0; i < n; ++i) ?? ??? ?{ ?? ??? ??? ?_str[i] = ch; ?? ??? ?} ?? ??? ?_str[_size] = '\0'; ?? ?}
拷貝構造:
?? ?string(const string& s) ?? ??? ?:_str(nullptr) ?? ?{ ?? ??? ?string tmp(s._str); ?? ??? ?swap(tmp); ?? ?}
用s._str
去構造臨時對象tmp,這里引用傳參s是s1的別名,tmp調用構造函數開空間拷貝數據,所以最后tmp和s1是一樣的數據一樣的大小,而tmp的空間是s2想要的,所以把他們交換。這樣s2就達到深拷貝的效果了。
tmp是局部對象,出函數作用域會調用析構函數,而s2的_str指向的位置是隨機值,把tmp和s2交換后tmp的_str就變成了隨機值,不能對一個隨機的位置進行釋放,所以先在參數列表中把s2的_str指向nullptr
。
另外還需要提供一個swap函數交換兩個對象:
?? ?void swap(string& s) ?? ?{ ?? ??? ?::swap(_str, s._str); ?? ??? ?::swap(_size, s._size); ?? ??? ?::swap(_capacity, s._capacity); ?? ?}
賦值重載:
?
?? ?string& operator=(string s) ?? ?{ ?? ??? ?swap(s); ?? ??? ?return *this; ?? ?} string s1(“hello”); string s2(“world”); s2 = s1;
s1傳值傳參給s,調用拷貝構造深拷貝,s和s1是一樣的,把s和s2交換,出函數作用域后形參s調用析構函數釋放資源。
析構函數:
?? ?~string() ?? ?{ ?? ??? ?delete[] _str; ?? ??? ?_str = nullptr; ?? ??? ?_size = _capacity = 0; ?? ?}
迭代器
迭代器是一個像指針一樣的東西,有可能是指針,也有可能不是指針。
begin()
返回第一個有效數據位置的迭代器end()
返回最后一個有效數據的下一個位置的迭代器vector/string
這種底層用連續一段空間存儲數據,支持[ ] + 下標訪問,迭代器用原生指針即可。
普通迭代器:
?? ?typedef char* iterator; ?? ? ?? ?iterator begin() ?? ?{ ?? ??? ?return _str; ?? ?} ?? ? ?? ?iterator end() ?? ?{ ?? ??? ?return _str + _size; ?? ?}
const迭代器:
?typedef const char* const_iterator; ?? ? ?? ?const_iterator begin() const ?? ?{ ?? ??? ?return _str; ?? ?} ?? ? ?? ?const_iterator end() const ?? ?{ ?? ??? ?return _str + _size; ?? ?}
重載運算符[ ]
也一樣提供非const
版本和const
版本
?char& operator[](size_t pos) ?? ?{ ?? ??? ?assert(pos < _size); ?? ??? ?return _str[pos]; ?? ?} ?? ? ?? ?const char& operator[](size_t pos) const ?? ?{ ?? ??? ?assert(pos < _size); ?? ??? ?return _str[pos]; ?? ?}
現在可以創建一個string
對象并且遍歷了。
三、幾種常見函數
reserve()
reserve()
函數用來修改字符串容量的大小。如果申請空間的newcapacity
大于當前的capacity,則分配新的存儲空間,并使capacity
等于或大于 newcapacity。如果newcapacity小于當前容量,則是一個非綁定收縮請求。
從C++20起如果newcapacity
小于或等于當前容量,則沒有效果。
? ?void reserve(size_t n) ?? ?{ ?? ??? ?if (n > _capacity) ?? ??? ?{ ?? ??? ??? ?char* tmp = new char[n + 1]; ?? ??? ??? ?strcpy(tmp, _str); ?? ??? ??? ?delete[] _str; ?? ??? ??? ?_str = tmp; ?? ??? ??? ?_capacity = n; ?? ??? ?} ?? ?}
resize()
resize()
用來將字符串大小調整為n個字符的長度。
如果 n 小于當前字符串長度,則將當前size縮短為n。
如果 n 大于當前字符串長度,則通過在末尾插入所需數量的字符來擴展當前內容,以達到 n 的大小。 如果指定了字符,則將新元素初始化為該字符,否則初始化為空字符。
?void resize(size_t n, char ch = '\0') ?? ?{ ?? ??? ?if (n < _size) ?? ??? ?{ ?? ??? ??? ?_str[n] = '\0'; ?? ??? ??? ?_size = n; ?? ??? ?} ?? ??? ?else ?? ??? ?{ ?? ??? ??? ?if (n > _capacity) ?? ??? ??? ?{ ?? ??? ??? ??? ?reserve(n); ?? ??? ??? ?} ?? ??? ??? ?for (size_t i = _size; i < n; ++i) ?? ??? ??? ?{ ?? ??? ??? ??? ?_str[i] = ch; ?? ??? ??? ?} ?? ??? ??? ?_size = n; ?? ??? ??? ?_str[_size] = '\0'; ?? ??? ?} ?? ?}
push_back()
將給定字符加到字符串的末尾。
?void push_back(char ch) ?? ?{ ?? ??? ?if (_size >= _capacity) ?? ??? ?{ ?? ??? ??? ?size_t newcapacity = _capacity == 0 ? 4 : 2 * _capacity; ?? ??? ??? ?reserve(newcapacity); ?? ??? ?} ?? ??? ?_str[_size] = ch; ?? ??? ?++_size; ?? ??? ?_str[_size] = '\0';?? ? ?? ?}
append()
在字符串結尾添加字符串
?void append(const char* str) ?? ?{ ?? ??? ?size_t len = strlen(str); ?? ??? ?if (_size + len > _capacity) ?? ??? ?{ ?? ??? ??? ?reserve(_size + len); ?? ??? ?} ?? ??? ?strcpy(_str + _size, str); ?? ??? ?_size += len; ?? ?}
有了push_back()
和append()
就很方便重載+=
重載+=
右操作數為字符:
? ?string& operator+=(char ch) ?? ?{ ?? ??? ?push_back(ch); ?? ??? ?return *this; ?? ?}
右操作數為字符串:
?? ?string& operator+=(const char* str) ?? ?{ ?? ??? ?append(str); ?? ??? ?return *this; ?? ?}
右操作數為對象:
?? ?string& operator+=(const string& s) ?? ?{ ?? ??? ?*this += s._str; ?? ??? ?return *this; ?? ?}
insert()
在字符串任意位置插入一個字符或字符串。push_back()
和append()
都可以復用insert()
。
插入字符:
?? ?string& insert(size_t pos, char ch) ?? ?{ ?? ??? ?assert(pos <= _size); ?? ??? ?if (_size == _capacity) ?? ??? ?{ ?? ??? ??? ?size_t newcapacity = _capacity == 0 ? 4 : 2 * _capacity; ?? ??? ??? ?reserve(newcapacity); ?? ??? ?} ?? ??? ?for (size_t i = _size + 1; i > pos; --i) ?? ??? ?{ ?? ??? ??? ?_str[i] = _str[i - 1]; ?? ??? ?} ?? ??? ?_str[pos] = ch; ?? ??? ?++_size; ?? ??? ?return *this; ?? ?}
插入字符串:
?string& insert(size_t pos, const char* str) ?? ?{ ?? ??? ?assert(pos <= _size); ?? ??? ?size_t len = strlen(str); ?? ??? ?if (len + _size > _capacity) ?? ??? ?{ ?? ??? ??? ?reserve(len + _size); ?? ??? ?} ?? ??? ?for (size_t i = _size + len; i >= (pos + len); --i) ?? ??? ?{ ?? ??? ??? ?_str[i] = _str[i - len]; ?? ??? ?} ?? ??? ?for (size_t i = 0; i < len; ++i) ?? ??? ?{ ?? ??? ??? ?_str[pos + i] = str[i]; ?? ??? ?} ?? ??? ?_size += len; ?? ??? ?return *this; ?? ?}
erase()
刪除字符串的一部分,減少它的長度,如果沒給參數len就會從pos位置直接刪到最后。
?string& erase(size_t pos = 0, size_t len = npos) ?? ?{ ?? ??? ?assert(pos < _size); ?? ??? ?if (len >= (_size - pos)) ?? ??? ?{ ?? ??? ??? ?_str[pos] = '\0'; ?? ??? ??? ?_size = pos; ?? ??? ?} ?? ??? ?else ?? ??? ?{ ?? ??? ??? ?for (size_t i = pos + len; i <= _size; ++i) ?? ??? ??? ?{ ?? ??? ??? ??? ?_str[i - len] = _str[i]; ?? ??? ??? ?} ?? ??? ??? ?_size -= len; ?? ??? ?} ?? ??? ?return *this; ?? ?}
find()
查找從pos
位置開始第一個給定字符或字符串。找到了返回對應字符或子串第一個字符第一次出現的位置,沒找到返回npos。
查找字符:
?size_t find(char ch, size_t pos = 0) ?? ?{ ?? ??? ?for (size_t i = pos; i < _size; ++i) ?? ??? ?{ ?? ??? ??? ?if (_str[i] == ch) ?? ??? ??? ??? ?return i; ?? ??? ?} ?? ??? ?return npos; ?? ?}
查找字符串:
? ?size_t find(const char* sub, size_t pos = 0) ?? ?{ ?? ??? ?const char* p = strstr(_str + pos, sub); ?? ??? ?if (p) ?? ??? ??? ?return p - _str; ?? ??? ?return npos; ?? ?}
四、操作符重載
流插入<<
?? ?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 ch = in.get(); ?? ??? ?while (ch != ' ' && ch != '\n') ?? ??? ?{ ?? ??? ??? ?s += ch; ?? ??? ??? ?ch = in.get(); ?? ??? ?} ?? ??? ?return in; ?? ?}
其他運算符重載和一些簡單的函數在完整代碼給出。
原文鏈接:https://blog.csdn.net/weixin_45806959/article/details/122410137
相關推薦
- 2022-11-01 Android串口通訊SerialPort的使用詳情_Android
- 2022-09-24 Go?類型轉化工具庫cast函數詳解_Golang
- 2022-10-07 C語言直接插入排序算法介紹及示例_C 語言
- 2023-02-05 C語言模擬實現memmove的示例代碼_C 語言
- 2022-07-17 SQL?Server中的約束(constraints)詳解_MsSql
- 2022-07-07 C#多線程之線程鎖_C#教程
- 2022-02-19 使用.Net?Core實現的一個圖形驗證碼功能_實用技巧
- 2022-03-28 Python獲取網絡時間戳的兩種方法詳解_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支