• 【C++】string的底层剖析以及模拟实现


    一、字符串类的认识

            C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数, 但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。在OJ中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本 都使用string类,很少有人去使用C库中的字符串操作函数。为了增加自己对于string的理解,自己将模仿库中string类有的方法,设计一个简单的string类。其中类成员包括以下:

    1. class string
    2. {
    3. private:
    4. char* _str;//字符串首地址
    5. size_t _capacity;//字符串容量
    6. size_t _size;//有效数据的个数
    7. public:
    8. typedef char* iterator;
    9. }

    二、库中string常用的方法

            我主要会实现string中经常会用到的方法,若大家想要了解更多关于string的细节,可以登录这个C++查询网站https://cplusplus.com/reference/自行查询下面是一些常用方法以及代码片段,可能前面出现的方法会用到后面出现的方法的实现,若有疑问可以看最后面的完整代码

    正向迭代器

    1. iterator begin()
    2. {
    3. return _str;
    4. }
    5. iterator end()
    6. {
    7. return _str + _size;
    8. }

    +=

    1. string& operator+=(char c)
    2. {
    3. if (_size == _capacity)
    4. {
    5. _capacity = _capacity == 0 ? 4 : 2 * _capacity;
    6. char* tmp = new char[_capacity +1];
    7. strcpy(tmp, _str);
    8. delete[] _str;
    9. _str = tmp;
    10. }
    11. _str[_size] = c;
    12. _str[_size + 1] = '\0';
    13. _size++;
    14. return *this;
    15. }
    16. string& operator+=(const char* str)
    17. {
    18. append(str);
    19. return *this;
    20. }

    push_back(尾插)

    1. void push_back(char c)
    2. {
    3. *this += c;
    4. }

     append(在字符串末尾追加)

    1. void append(const char* str)
    2. {
    3. int i = 0;
    4. while (str[i])
    5. {
    6. push_back(str[i]);
    7. i++;
    8. }
    9. }

      clear(清除掉字符串的数据)

    1. void clear()
    2. {
    3. _size = 0;
    4. _str[0] = '\0';
    5. }

       swap(交换两个字符串的内容)

    1. void swap(string& s)
    2. {
    3. std::swap(_str,s._str);
    4. std::swap(_size, s._size);
    5. std::swap(_capacity, s._capacity);
    6. }

      c_str(返回字符串的首地址)

    1. const char* c_str()const
    2. {
    3. return _str;
    4. }

     resize(将字符串设定为指定大小,字符串占满所开辟的空间)

    1. void resize(size_t n, char c = '\0')
    2. {
    3. if (n > _capacity)
    4. {
    5. reserve(n);
    6. for (int i = _size; i < _capacity; i++)
    7. {
    8. _str[i] = c;
    9. }
    10. _size = _capacity;
    11. }
    12. else
    13. {
    14. _size = n;
    15. }
    16. }

     reserve(预开辟出空间,字符串还是原来的大小(一般不缩容))

    1. void reserve(size_t n)
    2. {
    3. if (n > _capacity)
    4. {
    5. _capacity = n;
    6. char* tmp = new char[_capacity + 1];
    7. strcpy(tmp, _str);
    8. delete[] _str;
    9. _str = tmp;
    10. }
    11. }

      find(返回字符c在string中第一次出现的位置/返回子串s在string中第一次出现的位置

    1. size_t find(char c, size_t pos = 0) const
    2. {
    3. for (size_t i = pos; i < _size; i++)
    4. {
    5. if (_str[i] == c)
    6. return i;
    7. }
    8. return std::string::npos;
    9. }
    10. size_t find(const char* s, size_t pos = 0) const
    11. {
    12. const char* ptr = std::strstr(_str + pos, s);
    13. if (ptr == nullptr)
    14. return std::string::npos;
    15. else
    16. {
    17. return ptr - _str;
    18. }
    19. }

    insert(在pos位置上插入字符c/字符串str,并返回该字符的位置)

     

    1. string& insert(size_t pos, char c)
    2. {
    3. if (_size == _capacity)
    4. {
    5. reserve(_capacity == 0 ? 4 : 2 * _capacity);
    6. }
    7. size_t end = _size - 1;
    8. while (end >= pos)
    9. {
    10. _str[end + 1] = _str[end];
    11. end--;
    12. }
    13. _str[pos] = c;
    14. return *this;
    15. }
    16. string& insert(size_t pos, const char* str)
    17. {
    18. int len = 0;
    19. while (str[len++]);
    20. if (_size + len > _capacity)
    21. {
    22. reserve(_size + len);
    23. }
    24. memmove(_str + pos + len, _str + pos, len * sizeof(char));
    25. for (int i = pos; i < pos + len; i++)
    26. {
    27. _str[i] = str[i - pos];
    28. }
    29. _size += len;
    30. return *this;
    31. }

    erase(删除pos位置上的元素,并返回该string)

    1. string& erase(size_t pos, size_t len)
    2. {
    3. memmove(_str + pos, _str + pos + len, (_size - pos-len) * sizeof(char));
    4. _size -= len;
    5. return *this;
    6. }

    三、完整代码

    1. //string.h
    2. #pragma once
    3. #define _CRT_SECURE_NO_WARNINGS 1
    4. #include
    5. #include
    6. //using namespace std;
    7. namespace sxb
    8. {
    9. class string
    10. {
    11. friend std::ostream& operator<<(std::ostream& _cout, const string& s);
    12. friend std::istream& operator>>(std::istream& _cin, string& s);
    13. private:
    14. char* _str;
    15. size_t _capacity;
    16. size_t _size;
    17. public:
    18. typedef char* iterator;
    19. public:
    20. string(const char* str = "")
    21. {
    22. //_str = str;
    23. int len = 0;
    24. while(str[len] != ' ' && str[len] != '\0')
    25. {
    26. len++;
    27. }
    28. _str = new char[len + 1];
    29. for (int i = 0; i < len; i++)
    30. {
    31. _str[i] = str[i];
    32. }
    33. _str[len] = '\0';
    34. _capacity = len;
    35. _size = len;
    36. }
    37. string(const string& s)
    38. {
    39. _str = new char[s.size() + 1];
    40. strcpy(_str, s.c_str());
    41. _str[s.size()] = '\0';
    42. _capacity = s.size();
    43. _size = s.size();
    44. }
    45. string& operator=(const string& s)
    46. {
    47. for (int i = 0; i < size(); i++)
    48. {
    49. _str += s[i];
    50. }
    51. return *this;
    52. }
    53. ~string()
    54. {
    55. delete[] _str;
    56. _size = 0;
    57. _capacity = 0;
    58. }
    59. //
    60. // iterator
    61. iterator begin()
    62. {
    63. return _str;
    64. }
    65. iterator end()
    66. {
    67. return _str + _size;
    68. }
    69. // /
    70. // // modify
    71. void push_back(char c)
    72. {
    73. *this += c;
    74. }
    75. string& operator+=(char c)
    76. {
    77. if (_size == _capacity)
    78. {
    79. _capacity = _capacity == 0 ? 4 : 2 * _capacity;
    80. char* tmp = new char[_capacity +1];
    81. strcpy(tmp, _str);
    82. delete[] _str;
    83. _str = tmp;
    84. }
    85. _str[_size] = c;
    86. _str[_size + 1] = '\0';
    87. _size++;
    88. return *this;
    89. }
    90. void append(const char* str)
    91. {
    92. int i = 0;
    93. while (str[i])
    94. {
    95. push_back(str[i]);
    96. i++;
    97. }
    98. }
    99. string& operator+=(const char* str)
    100. {
    101. append(str);
    102. return *this;
    103. }
    104. void clear()
    105. {
    106. _size = 0;
    107. _str[0] = '\0';
    108. }
    109. void swap(string& s)
    110. {
    111. std::swap(_str,s._str);
    112. std::swap(_size, s._size);
    113. std::swap(_capacity, s._capacity);
    114. }
    115. const char* c_str()const
    116. {
    117. return _str;
    118. }
    119. ///
    120. capacity
    121. size_t size()const
    122. {
    123. return _size;
    124. }
    125. size_t capacity()const
    126. {
    127. return _capacity;
    128. }
    129. bool empty()const
    130. {
    131. return _str[0] == '\0';
    132. }
    133. void resize(size_t n, char c = '\0')
    134. {
    135. if (n > _capacity)
    136. {
    137. reserve(n);
    138. for (int i = _size; i < _capacity; i++)
    139. {
    140. _str[i] = c;
    141. }
    142. _size = _capacity;
    143. }
    144. else
    145. {
    146. _size = n;
    147. }
    148. }
    149. void reserve(size_t n)
    150. {
    151. if (n > _capacity)
    152. {
    153. _capacity = n;
    154. char* tmp = new char[_capacity + 1];
    155. strcpy(tmp, _str);
    156. delete[] _str;
    157. _str = tmp;
    158. }
    159. }
    160. ///
    161. access
    162. char& operator[](size_t index)
    163. {
    164. return _str[index];
    165. }
    166. const char& operator[](size_t index)const
    167. {
    168. return _str[index];
    169. }
    170. ///
    171. relational operators
    172. bool operator==(const string& s)
    173. {
    174. if (_size != s.size())
    175. return false;
    176. for (int i = 0; i < _size; i++)
    177. {
    178. if (_str[i] != s[i])
    179. return false;
    180. }
    181. return true;
    182. }
    183. bool operator!=(const string& s)
    184. {
    185. return !operator==(s);
    186. }
    187. 返回c在string中第一次出现的位置
    188. size_t find(char c, size_t pos = 0) const
    189. {
    190. for (size_t i = pos; i < _size; i++)
    191. {
    192. if (_str[i] == c)
    193. return i;
    194. }
    195. return std::string::npos;
    196. }
    197. 返回子串s在string中第一次出现的位置
    198. size_t find(const char* s, size_t pos = 0) const
    199. {
    200. const char* ptr = std::strstr(_str + pos, s);
    201. if (ptr == nullptr)
    202. return std::string::npos;
    203. else
    204. {
    205. return ptr - _str;
    206. }
    207. }
    208. 在pos位置上插入字符c/字符串str,并返回该字符的位置
    209. string& insert(size_t pos, char c)
    210. {
    211. if (_size == _capacity)
    212. {
    213. reserve(_capacity == 0 ? 4 : 2 * _capacity);
    214. }
    215. size_t end = _size - 1;
    216. while (end >= pos)
    217. {
    218. _str[end + 1] = _str[end];
    219. end--;
    220. }
    221. _str[pos] = c;
    222. return *this;
    223. }
    224. string& insert(size_t pos, const char* str)
    225. {
    226. int len = 0;
    227. while (str[len++]);
    228. if (_size + len > _capacity)
    229. {
    230. reserve(_size + len);
    231. }
    232. memmove(_str + pos + len, _str + pos, len * sizeof(char));
    233. for (int i = pos; i < pos + len; i++)
    234. {
    235. _str[i] = str[i - pos];
    236. }
    237. _size += len;
    238. return *this;
    239. }
    240. 删除pos位置上的元素,并返回该元素的下一个位置
    241. string& erase(size_t pos, size_t len)
    242. {
    243. memmove(_str + pos, _str + pos + len, (_size - pos-len) * sizeof(char));
    244. _size -= len;
    245. return *this;
    246. }
    247. };
    248. std::ostream& operator<<(std::ostream& _cout, const string& s)
    249. {
    250. for (int i = 0; i < s.size(); i++)
    251. {
    252. _cout << s[i];
    253. }
    254. return _cout;
    255. }
    256. std::istream& operator>>(std::istream& _cin, string& s)
    257. {
    258. char buffer[128];
    259. int len = 0;
    260. char bu = _cin.get();
    261. while (bu != ' ' && bu != '\n')
    262. {
    263. buffer[len] = bu;
    264. len++;
    265. bu = _cin.get();
    266. }
    267. for (int i = 0; i < len; i++)
    268. {
    269. s += buffer[i];
    270. }
    271. return _cin;
    272. }
    273. }

  • 相关阅读:
    Nginx实战
    ACM练习——第四天
    2022-10-19 mysql列存储引擎-exists子查询错误-问题定位分析
    【案例分享】IPSec VPN与NQA联动实现主备对等体和主备链路快速切换
    第十一章:Java集合
    基于springboot农机电招平台设计与实现的源码+文档
    RepViT: 从ViT视角重新审视移动CNN
    Day711. 档案类-Java8后最重要新特性
    【多级缓存】
    模仿学习(DMP与GMM应用)
  • 原文地址:https://blog.csdn.net/m0_74265792/article/details/136693513