• <string类模拟实现>——《C++初阶》


    为实现祖国统一而奋斗!为实现社会主义现代化而奋斗!为实现中华民族复兴而奋斗!
                                                                         ——By  一名社会主义建设积极分子
     

    目录

    一、实现概括:

    1.先实现一个简单的string,只考虑资源管理深浅拷贝问题(暂不考虑增删查改)

          对于浅拷贝的两个问题:

    2. string完善的增、删、查、改、使用的string 

    完整源码及注释:

    后记:●由于作者水平有限,文章难免存在谬误之处,敬请读者斧正,俚语成篇,恳望指教!                                     ——By 作者:新晓·故知 


    一、实现概括:

    模拟实现string类,最主要是实现string类的构造、拷贝构造、赋值运算符重载以及析构函数。根据string的底层原理,实现模拟string使其与库里的string(即std::string)具有相似的功能。由于库里的string类的功能较多,这里只模拟实现了较为常用的功能,

    例如:iterator(模拟的string迭代器)、push_back、insert、reserve、resize、find、erase、c_str、ostream重载、istream重载、赋值运算符重载、[ ]重载、append以及比较运算符的重载等,甚至深拷贝构造函数的现代写法(资本写法)、赋值运算符重载的现代写法(资本写法)等。std::string中的功能较多,学习使用可登录cplusplus官网,参见string文档。

    1.先实现一个简单的string,只考虑资源管理深浅拷贝问题(暂不考虑增删查改)

    (1)string.h

    (2)test.cpp:

     

    深拷贝:

    深拷贝:使得值相同,空间大小相同,但空间地址不同

     

    对于浅拷贝的两个问题:

    1.多次析构同一空间:引用计数,即最后一个拷贝构造的对象是否资源

    2.一个对象修改会影响其他对象:做深拷贝,写时拷贝

    2. string完善的增、删、查、改、使用的string 

     string.h:

     test.cpp:

    完整源码及注释:

    (1)string.h:

    1. #pragma once
    2. #define _CRT_SECURE_NO_WARNINGS
    3. #include
    4. #include
    5. #include
    6. using namespace std;
    7. //模拟实现string
    8. //1.先实现一个简单的string,只考虑资源管理深浅拷贝问题
    9. //自定义命名空间,防止与库中的冲突
    10. //namespace my
    11. //{
    12. // //先实现一个简单的string,只考虑资源管理深浅拷贝问题
    13. // //暂不考虑增删查改
    14. // class string
    15. // {
    16. // public:
    17. // //构造函数
    18. // string(const char* str)
    19. // :_str(new char[strlen(str) + 1])
    20. // {
    21. // //不能直接 _str=str; 因为会权限放大
    22. // strcpy(_str, str); //也拷贝了\0
    23. // }
    24. // //深拷贝函数 s2(s1)
    25. // string(const string& s)
    26. // :_str(new char[strlen(s._str) + 1])
    27. // {
    28. // strcpy(_str, s._str);
    29. // }
    30. // ~string()
    31. // {
    32. // if (_str)
    33. // {
    34. // delete[] _str;
    35. // }
    36. // }
    37. // //s1=s3 ——>s1.operator=(&s1,s3)
    38. // //赋值重载函数
    39. // string& operator = (const string& s)
    40. // {
    41. // if (this != &s) //解决s1=s1,自己释放自己的空间
    42. // {
    43. // //先删除,再开辟赋值
    44. // //如果new开辟失败,那s1作为原始数据被删除
    45. // /*delete[] _str;
    46. // _str = new char[strlen(s._str) + 1];
    47. // strcpy(_str, s._str);*/
    48. // //先保存,再开辟赋值
    49. // char* tmp = new char[strlen(s._str) + 1];
    50. // strcpy(tmp, s._str);
    51. // delete[] _str;
    52. // _str = tmp;
    53. // }
    54. // return *this;
    55. // }
    56. // //c_str是string中的一个函数,具体详见string文档
    57. // //获取等效的字符串
    58. // const char* c_str() const
    59. // {
    60. // return _str;
    61. // }
    62. // //重载[]
    63. // char& operator[](size_t pos)
    64. // {
    65. // assert(pos < strlen(_str));
    66. // return _str[pos];
    67. // }
    68. // //计算字符串大小
    69. // size_t size()
    70. // {
    71. // return strlen(_str);
    72. // }
    73. //
    74. // private:
    75. // char* _str;
    76. //
    77. // };
    78. //}
    79. //
    80. 2.string完善的增删查改和使用的string
    81. //namespace my
    82. //{
    83. // class string
    84. // {
    85. // public:
    86. // 构造函数
    87. // //string(const char* str)
    88. // // :_size(strlen(str))
    89. // // ,_capacity(_size)
    90. // //{
    91. // // //要注意初始化顺序,取决于类的声明顺序
    92. // // _str = new char[_capacity + 1];
    93. // // //不能直接 _str=str; 因为会权限放大
    94. // // strcpy(_str, str); //也拷贝了\0
    95. // //}
    96. // 默认构造函数(无参使用的)
    97. // //string()
    98. // // :_size(0)
    99. // // ,_capacity(0)
    100. // //{
    101. // // _str = new char[1]; //将_str初始化为空字符串,string库就是这种做法
    102. // // _str[0] = '0';
    103. // //}
    104. //
    105. // //默认构造函数(全缺省版)
    106. // string(const char* str="") // ""、"\0"均可以,'\0'是字符
    107. // :_size(strlen(str))
    108. // , _capacity(_size)
    109. // {
    110. // //要注意初始化顺序,取决于类的声明顺序
    111. // _str = new char[_capacity + 1];
    112. // //不能直接 _str=str; 因为会权限放大
    113. // strcpy(_str, str); //也拷贝了\0
    114. // }
    115. // 深拷贝函数版本1 s2(s1)
    116. // //string(const string& s)
    117. // // :_str(new char[strlen(s._str) + 1])
    118. // //{
    119. // // strcpy(_str, s._str);
    120. // //}
    121. // //深拷贝函数版本2 s2(s1)
    122. // string(const string& s)
    123. // :_size(strlen(s._str))
    124. // ,_capacity(_size)
    125. // {
    126. // _str=new char[_capacity + 1];
    127. // strcpy(_str, s._str);
    128. // }
    129. //
    130. // //析构函数
    131. // ~string()
    132. // {
    133. // if (_str)
    134. // {
    135. // delete[] _str;
    136. // }
    137. // }
    138. // //s1=s3 ——>s1.operator=(&s1,s3)
    139. // //赋值重载函数
    140. // string& operator = (const string& s)
    141. // {
    142. // if (this != &s) //解决s1=s1,自己释放自己的空间
    143. // {
    144. // //先保存,再开辟赋值
    145. // char* tmp = new char[s._capacity + 1];
    146. // strcpy(tmp, s._str);
    147. // delete[] _str;
    148. // _str = tmp;
    149. // _size = s._size;
    150. // _capacity = s._capacity;
    151. // }
    152. // return *this;
    153. // }
    154. // //c_str是string中的一个函数,具体详见string文档
    155. // //获取等效的字符串
    156. // const char* c_str() const
    157. // {
    158. // return _str;
    159. // }
    160. // //重载[]
    161. // char& operator[](size_t pos)
    162. // {
    163. // assert(pos < _size);
    164. // return _str[pos];
    165. // }
    166. // //重载[] const 提供两个版本的重载[] ,普通对象和const对象都可以调用
    167. // const char& operator[](size_t pos) const
    168. // {
    169. // assert(pos < _size);
    170. // return _str[pos];
    171. // }
    172. // //计算字符串大小
    173. // //size_t size(const string* this)
    174. // size_t size() const
    175. // {
    176. // return _size;
    177. // }
    178. //
    179. // size_t capacity() const
    180. // {
    181. // return _capacity;
    182. // }
    183. // 尾插数据
    184. // //void push_back(char ch)
    185. // //{
    186. // // if (_size == _capacity) //其实为_capacity开辟的多一个为\0存储的空间,但那个不参与比较
    187. // // {
    188. // // char* tmp = new char[_capacity * 2 + 1];
    189. // // strcpy(tmp, _str);
    190. // // delete[] _str;
    191. // // _str = tmp;
    192. // // _capacity *= 2;
    193. // // }
    194. // // _str[_size] = ch;
    195. // // ++_size;
    196. // // _str[_size] = '\0';
    197. // //}
    198. //
    199. // //尾插也可以使用+=(附用push_back)
    200. // string& operator+=(char ch)
    201. // {
    202. // push_back(ch);
    203. // return *this;
    204. // }
    205. // //预留扩容
    206. // void reserve(size_t n)
    207. // {
    208. // if (n > _capacity)
    209. // {
    210. // char* tmp = new char[n + 1];
    211. // strcpy(tmp, _str);
    212. // delete[] _str;
    213. // _str = tmp;
    214. // _capacity = n;
    215. // }
    216. // }
    217. // //尾插数据——附用reserve
    218. // void push_back(char ch)
    219. // {
    220. // //if (_size == _capacity) //其实为_capacity开辟的多一个为\0存储的空间,但那个不参与比较
    221. // //{
    222. // // //reserve( _capacity * 2);若_capacity为0,则出现bug
    223. // // reserve(_capacity==0 ? 4 : _capacity * 2);
    224. // //}
    225. // //_str[_size] = ch;
    226. // //++_size;
    227. // //_str[_size] = '\0';
    228. //
    229. // //附用insert
    230. // insert(_size, ch);
    231. // }
    232. // //追加到字符
    233. // void append(const char*str)
    234. // {
    235. // /*size_t len = _size + strlen(str);
    236. // if (len > _capacity)
    237. // {
    238. // reserve(len);
    239. // }
    240. // strcpy(_str + _size, str);
    241. // _size = len;*/
    242. // //附用insert
    243. // insert(_size, str);
    244. // }
    245. // //尾插也可以使用+=(附用append)
    246. // string& operator+=(const char* str)
    247. // {
    248. // append(str);
    249. // return *this;
    250. // }
    251. // //扩空间+初始化
    252. // //删除部分数据,保留前n个
    253. // void resize(size_t n, char ch = '\0')
    254. // {
    255. // //考虑到内存对齐,可能开辟的空间与n有些许微小出入
    256. // if (n < _size)
    257. // {
    258. // _size = n;
    259. // _str[_size] = '\0';
    260. // }
    261. // else
    262. // {
    263. // if (n > _capacity)
    264. // {
    265. // reserve(n);
    266. // }
    267. // for (size_t i = _size; i < n; ++i)
    268. // {
    269. // _str[i] = ch;
    270. // }
    271. // _size = n;
    272. // _str[_size] = '\0';
    273. // }
    274. // }
    275. //
    276. // //迭代器
    277. // typedef char* iterator;
    278. // typedef const char* const_iterator;
    279. //
    280. // iterator begin()
    281. // {
    282. // return _str;
    283. // }
    284. // iterator end()
    285. // {
    286. // return _str + _size;
    287. // }
    288. // const_iterator begin() const
    289. // {
    290. // return _str;
    291. // }
    292. // const_iterator end() const
    293. // {
    294. // return _str + _size;
    295. // }
    296. // //头插数据
    297. // //持续头插,不如尾插逆置
    298. // //插入字符
    299. // string& insert(size_t pos, char ch)
    300. // {
    301. // assert(pos <= _size); //pos = _size相当于尾插
    302. // if (_size == _capacity)
    303. // {
    304. // reserve(_capacity == 0 ? 4 : _capacity * 2);
    305. // }
    306. // //size_t end = _size;
    307. // //while (end >= pos) //--end会造成负数,而--end是size_t类型
    308. // //{
    309. // // _str[end + 1] = _str[end];
    310. // // --end;
    311. // //}
    312. // 解决1:强转类型
    313. // //int end = _size;
    314. // //while (end >=(int) pos) //--end会造成负数,而--end是size_t类型
    315. // //{
    316. // // _str[end + 1] = _str[end];
    317. // // --end;
    318. // //}
    319. // //解决2:修改end位置
    320. // size_t end = _size+1;
    321. // while (end > pos) //end等于0就停止
    322. // {
    323. // _str[end ] = _str[end-1];
    324. // --end;
    325. // }
    326. // _str[pos] = ch;
    327. // _size ++;
    328. // return *this;
    329. // }
    330. // //插入字符串
    331. // string& insert(size_t pos,const char* str)
    332. // {
    333. // assert(pos <= _size);
    334. // size_t len=strlen(str);
    335. // if (_size + len > _capacity)
    336. // {
    337. // reserve(_size + len);
    338. // }
    339. // size_t end = _size + len;
    340. // while (end > pos + len - 1) //或者while (end >= pos + len) ,但pos、len均为0就有问题
    341. // {
    342. // _str[end] = _str[end - len];
    343. // --end;
    344. // }
    345. // strncpy(_str + pos, str, len); //不能使用strcpy
    346. // _size += len;
    347. // return *this;
    348. // }
    349. // //删除
    350. // string& erase(size_t pos, size_t len=npos)
    351. // {
    352. // assert(pos < _size);
    353. // if (len == npos || pos + len >= _size)
    354. // {
    355. // _str[pos] = '\0';
    356. // _size = pos;
    357. // }
    358. // else
    359. // {
    360. // size_t begin = pos + len;
    361. // while (begin <= _size)
    362. // {
    363. // _str[begin - len] = _str[begin];
    364. // ++begin;
    365. // }
    366. // _size -= len;
    367. // }
    368. // return *this;
    369. // }
    370. // //查找字符
    371. // //The position of the first character of the first match.
    372. // //If no matches were found, the function returns string::npos.
    373. // size_t find(char ch,size_t pos=0)
    374. // {
    375. // for (; pos < _size; ++pos)
    376. // {
    377. // if (_str[pos] == ch)
    378. // {
    379. // return pos;
    380. // }
    381. // }
    382. // return npos;
    383. // }
    384. // //查找字符串
    385. // size_t find(const char*str, size_t pos = 0)
    386. // {
    387. // const char* p = strstr(_str + pos, str); //strstr暴力算法
    388. // if (p == nullptr)
    389. // {
    390. // return npos;
    391. // }
    392. // else
    393. // {
    394. // return p - _str;
    395. // }
    396. // }
    397. // void clear()
    398. // {
    399. // _str[0] = '\0';
    400. // _size = 0;
    401. // }
    402. // private:
    403. // char* _str;
    404. // size_t _size; //有效字符个数,不包含\0
    405. // size_t _capacity; //实际存储的有效字符的空间
    406. // const static size_t npos;
    407. //
    408. // };
    409. // //定义
    410. // const size_t string::npos = -1;
    411. // //这里不是成员函数,不在类里
    412. // //运算符<重载
    413. // bool operator<(const string& s1, const string& s2)
    414. // {
    415. // return strcmp(s1.c_str(), s2.c_str()) < 0;
    416. // }
    417. // //运算符==重载
    418. // bool operator==(const string& s1, const string& s2)
    419. // {
    420. // return strcmp(s1.c_str(), s2.c_str()) == 0;
    421. // }
    422. // //运算符<=重载
    423. // bool operator<=(const string& s1, const string& s2)
    424. // {
    425. // return s1 < s2 || s1 == s2;
    426. // }
    427. // //运算符>重载 (附用<=实现)
    428. // bool operator>(const string& s1, const string& s2)
    429. // {
    430. // return !(s1 <= s2);
    431. // }
    432. // //运算符>=重载 (附用<实现)
    433. // bool operator>=(const string& s1, const string& s2)
    434. // {
    435. // return !(s1 < s2);
    436. // }
    437. // //运算符!=重载 (附用==实现)
    438. // bool operator!=(const string& s1, const string& s2)
    439. // {
    440. // return !(s1 == s2);
    441. // }
    442. // //流运算符重载
    443. // ostream& operator<<(ostream& out, const string& s)
    444. // {
    445. // //out << s.c_str(); //无法打印不可见字符\0
    446. // for (auto ch : s)
    447. // {
    448. // out << ch;
    449. // }
    450. // return out;
    451. // }
    452. // istream& operator>>(istream& in, string& s)
    453. // {
    454. // //s.clear();
    455. // //char ch;
    456. // in >> ch;
    457. // //ch = in.get();
    458. // //while (ch != ' ' && ch != '\n')
    459. // //{
    460. // // s += ch;
    461. // // //in >> ch;
    462. // // ch = in.get();
    463. // //}
    464. // //return in;
    465. // //优化
    466. // s.clear();
    467. // char ch;
    468. // ch = in.get();
    469. // char buff[128] = { '\0' };
    470. // size_t i = 0;
    471. // while (ch != ' ' && ch != '\n')
    472. // {
    473. // buff[i++] = ch;
    474. // if (i == 127)
    475. // {
    476. // s += buff;
    477. // memset(buff, '\0', 128);
    478. // i = 0;
    479. // }
    480. // ch = in.get();
    481. // }
    482. // s += buff;
    483. // return in;
    484. // }
    485. // //getline
    486. //
    487. //}
    488. //3.string完善的增删查改和使用的string(现代写法)
    489. namespace my
    490. {
    491. class string
    492. {
    493. public:
    494. 构造函数
    495. //string(const char* str)
    496. // :_size(strlen(str))
    497. // ,_capacity(_size)
    498. //{
    499. // //要注意初始化顺序,取决于类的声明顺序
    500. // _str = new char[_capacity + 1];
    501. // //不能直接 _str=str; 因为会权限放大
    502. // strcpy(_str, str); //也拷贝了\0
    503. //}
    504. 默认构造函数(无参使用的)
    505. //string()
    506. // :_size(0)
    507. // ,_capacity(0)
    508. //{
    509. // _str = new char[1]; //将_str初始化为空字符串,string库就是这种做法
    510. // _str[0] = '0';
    511. //}
    512. //默认构造函数(全缺省版)
    513. string(const char* str = "") // ""、"\0"均可以,'\0'是字符
    514. :_size(strlen(str))
    515. , _capacity(_size)
    516. {
    517. //要注意初始化顺序,取决于类的声明顺序
    518. _str = new char[_capacity + 1];
    519. //不能直接 _str=str; 因为会权限放大
    520. strcpy(_str, str); //也拷贝了\0
    521. }
    522. 深拷贝函数版本1 s2(s1)
    523. //string(const string& s)
    524. // :_str(new char[strlen(s._str) + 1])
    525. //{
    526. // strcpy(_str, s._str);
    527. //}
    528. 深拷贝函数版本2 s2(s1) //传统写法:本分实现,自劳
    529. //string(const string& s)
    530. // :_size(strlen(s._str))
    531. // , _capacity(_size)
    532. //{
    533. // _str = new char[_capacity + 1];
    534. // strcpy(_str, s._str);
    535. //}
    536. //深拷贝函数版本3 s2(s1) //现代写法:剥削行为,借他人之手,行私利,但简单
    537. //tmp去调用构造函数:s1->s2:构造函数->拷贝构造函数->构造函数->swap
    538. //tmp->s2
    539. void swap(string& s)
    540. {
    541. //库里的swap,可交换任意类型
    542. std::swap(_str, s._str);
    543. std::swap(_size, s._size);
    544. std::swap(_capacity, s._capacity);
    545. }
    546. string(const string& s)
    547. :_str(nullptr)
    548. , _size(0)
    549. , _capacity(0)
    550. {
    551. string tmp(s._str); //tmp是局部对象,出作用域会调用析构函数
    552. /*swap(_str, tmp._str);
    553. swap(_size, tmp._size);
    554. swap(_capacity, tmp._capacity);*/
    555. swap(tmp);
    556. }
    557. //析构函数
    558. ~string()
    559. {
    560. if (_str)
    561. {
    562. delete[] _str;
    563. }
    564. }
    565. //s1=s3 ——>s1.operator=(&s1,s3)
    566. 赋值重载函数--版本1 传统写法
    567. //string& operator = (const string& s)
    568. //{
    569. // if (this != &s) //解决s1=s1,自己释放自己的空间
    570. // {
    571. // //先保存,再开辟赋值
    572. // char* tmp = new char[s._capacity + 1];
    573. // strcpy(tmp, s._str);
    574. // delete[] _str;
    575. // _str = tmp;
    576. // _size = s._size;
    577. // _capacity = s._capacity;
    578. // }
    579. // return *this;
    580. //}
    581. 赋值重载函数--版本2 现代写法
    582. //string& operator = (const string& s)
    583. //{
    584. // if (this != &s) //解决s1=s1,自己释放自己的空间
    585. // {
    586. // string tmp(s._str);
    587. // swap(tmp);
    588. // }
    589. // return *this;
    590. //}
    591. 赋值重载函数--版本3 现代写法
    592. string& operator = (string s) //传值传参,引用返回
    593. {
    594. swap(s);
    595. return *this;
    596. }
    597. //c_str是string中的一个函数,具体详见string文档
    598. //获取等效的字符串
    599. const char* c_str() const
    600. {
    601. return _str;
    602. }
    603. //重载[]
    604. char& operator[](size_t pos)
    605. {
    606. assert(pos < _size);
    607. return _str[pos];
    608. }
    609. //重载[] const 提供两个版本的重载[] ,普通对象和const对象都可以调用
    610. const char& operator[](size_t pos) const
    611. {
    612. assert(pos < _size);
    613. return _str[pos];
    614. }
    615. //计算字符串大小
    616. //size_t size(const string* this)
    617. size_t size() const
    618. {
    619. return _size;
    620. }
    621. size_t capacity() const
    622. {
    623. return _capacity;
    624. }
    625. 尾插数据
    626. //void push_back(char ch)
    627. //{
    628. // if (_size == _capacity) //其实为_capacity开辟的多一个为\0存储的空间,但那个不参与比较
    629. // {
    630. // char* tmp = new char[_capacity * 2 + 1];
    631. // strcpy(tmp, _str);
    632. // delete[] _str;
    633. // _str = tmp;
    634. // _capacity *= 2;
    635. // }
    636. // _str[_size] = ch;
    637. // ++_size;
    638. // _str[_size] = '\0';
    639. //}
    640. //尾插也可以使用+=(附用push_back)
    641. string& operator+=(char ch)
    642. {
    643. push_back(ch);
    644. return *this;
    645. }
    646. //预留扩容
    647. void reserve(size_t n)
    648. {
    649. if (n > _capacity)
    650. {
    651. char* tmp = new char[n + 1];
    652. strcpy(tmp, _str);
    653. delete[] _str;
    654. _str = tmp;
    655. _capacity = n;
    656. }
    657. }
    658. //尾插数据——附用reserve
    659. void push_back(char ch)
    660. {
    661. //if (_size == _capacity) //其实为_capacity开辟的多一个为\0存储的空间,但那个不参与比较
    662. //{
    663. // //reserve( _capacity * 2);若_capacity为0,则出现bug
    664. // reserve(_capacity==0 ? 4 : _capacity * 2);
    665. //}
    666. //_str[_size] = ch;
    667. //++_size;
    668. //_str[_size] = '\0';
    669. //附用insert
    670. insert(_size, ch);
    671. }
    672. //追加到字符
    673. void append(const char* str)
    674. {
    675. /*size_t len = _size + strlen(str);
    676. if (len > _capacity)
    677. {
    678. reserve(len);
    679. }
    680. strcpy(_str + _size, str);
    681. _size = len;*/
    682. //附用insert
    683. insert(_size, str);
    684. }
    685. //尾插也可以使用+=(附用append)
    686. string& operator+=(const char* str)
    687. {
    688. append(str);
    689. return *this;
    690. }
    691. //扩空间+初始化
    692. //删除部分数据,保留前n个
    693. void resize(size_t n, char ch = '\0')
    694. {
    695. //考虑到内存对齐,可能开辟的空间与n有些许微小出入
    696. if (n < _size)
    697. {
    698. _size = n;
    699. _str[_size] = '\0';
    700. }
    701. else
    702. {
    703. if (n > _capacity)
    704. {
    705. reserve(n);
    706. }
    707. for (size_t i = _size; i < n; ++i)
    708. {
    709. _str[i] = ch;
    710. }
    711. _size = n;
    712. _str[_size] = '\0';
    713. }
    714. }
    715. //迭代器
    716. typedef char* iterator;
    717. typedef const char* const_iterator;
    718. iterator begin()
    719. {
    720. return _str;
    721. }
    722. iterator end()
    723. {
    724. return _str + _size;
    725. }
    726. const_iterator begin() const
    727. {
    728. return _str;
    729. }
    730. const_iterator end() const
    731. {
    732. return _str + _size;
    733. }
    734. //头插数据
    735. //持续头插,不如尾插逆置
    736. //插入字符
    737. string& insert(size_t pos, char ch)
    738. {
    739. assert(pos <= _size); //pos = _size相当于尾插
    740. if (_size == _capacity)
    741. {
    742. reserve(_capacity == 0 ? 4 : _capacity * 2);
    743. }
    744. //size_t end = _size;
    745. //while (end >= pos) //--end会造成负数,而--end是size_t类型
    746. //{
    747. // _str[end + 1] = _str[end];
    748. // --end;
    749. //}
    750. 解决1:强转类型
    751. //int end = _size;
    752. //while (end >=(int) pos) //--end会造成负数,而--end是size_t类型
    753. //{
    754. // _str[end + 1] = _str[end];
    755. // --end;
    756. //}
    757. //解决2:修改end位置
    758. size_t end = _size + 1;
    759. while (end > pos) //end等于0就停止
    760. {
    761. _str[end] = _str[end - 1];
    762. --end;
    763. }
    764. _str[pos] = ch;
    765. _size++;
    766. return *this;
    767. }
    768. //插入字符串
    769. string& insert(size_t pos, const char* str)
    770. {
    771. assert(pos <= _size);
    772. size_t len = strlen(str);
    773. if (_size + len > _capacity)
    774. {
    775. reserve(_size + len);
    776. }
    777. size_t end = _size + len;
    778. while (end > pos + len - 1) //或者while (end >= pos + len) ,但pos、len均为0就有问题
    779. {
    780. _str[end] = _str[end - len];
    781. --end;
    782. }
    783. strncpy(_str + pos, str, len); //不能使用strcpy
    784. _size += len;
    785. return *this;
    786. }
    787. //删除
    788. string& erase(size_t pos, size_t len = npos)
    789. {
    790. assert(pos < _size);
    791. if (len == npos || pos + len >= _size)
    792. {
    793. _str[pos] = '\0';
    794. _size = pos;
    795. }
    796. else
    797. {
    798. size_t begin = pos + len;
    799. while (begin <= _size)
    800. {
    801. _str[begin - len] = _str[begin];
    802. ++begin;
    803. }
    804. _size -= len;
    805. }
    806. return *this;
    807. }
    808. //查找字符
    809. //The position of the first character of the first match.
    810. //If no matches were found, the function returns string::npos.
    811. size_t find(char ch, size_t pos = 0)
    812. {
    813. for (; pos < _size; ++pos)
    814. {
    815. if (_str[pos] == ch)
    816. {
    817. return pos;
    818. }
    819. }
    820. return npos;
    821. }
    822. //查找字符串
    823. size_t find(const char* str, size_t pos = 0)
    824. {
    825. const char* p = strstr(_str + pos, str); //strstr暴力算法
    826. if (p == nullptr)
    827. {
    828. return npos;
    829. }
    830. else
    831. {
    832. return p - _str;
    833. }
    834. }
    835. void clear()
    836. {
    837. _str[0] = '\0';
    838. _size = 0;
    839. }
    840. private:
    841. char* _str;
    842. size_t _size; //有效字符个数,不包含\0
    843. size_t _capacity; //实际存储的有效字符的空间
    844. const static size_t npos;
    845. };
    846. //定义
    847. const size_t string::npos = -1;
    848. //这里不是成员函数,不在类里
    849. //运算符<重载
    850. bool operator<(const string& s1, const string& s2)
    851. {
    852. return strcmp(s1.c_str(), s2.c_str()) < 0;
    853. }
    854. //运算符==重载
    855. bool operator==(const string& s1, const string& s2)
    856. {
    857. return strcmp(s1.c_str(), s2.c_str()) == 0;
    858. }
    859. //运算符<=重载
    860. bool operator<=(const string& s1, const string& s2)
    861. {
    862. return s1 < s2 || s1 == s2;
    863. }
    864. //运算符>重载 (附用<=实现)
    865. bool operator>(const string& s1, const string& s2)
    866. {
    867. return !(s1 <= s2);
    868. }
    869. //运算符>=重载 (附用<实现)
    870. bool operator>=(const string& s1, const string& s2)
    871. {
    872. return !(s1 < s2);
    873. }
    874. //运算符!=重载 (附用==实现)
    875. bool operator!=(const string& s1, const string& s2)
    876. {
    877. return !(s1 == s2);
    878. }
    879. //流运算符重载
    880. ostream& operator<<(ostream& out, const string& s)
    881. {
    882. //out << s.c_str(); //无法打印不可见字符\0
    883. for (auto ch : s)
    884. {
    885. out << ch;
    886. }
    887. return out;
    888. }
    889. istream& operator>>(istream& in, string& s)
    890. {
    891. //s.clear();
    892. //char ch;
    893. in >> ch;
    894. //ch = in.get();
    895. //while (ch != ' ' && ch != '\n')
    896. //{
    897. // s += ch;
    898. // //in >> ch;
    899. // ch = in.get();
    900. //}
    901. //return in;
    902. //优化
    903. s.clear();
    904. char ch;
    905. ch = in.get();
    906. char buff[128] = { '\0' };
    907. size_t i = 0;
    908. while (ch != ' ' && ch != '\n')
    909. {
    910. buff[i++] = ch;
    911. if (i == 127)
    912. {
    913. s += buff;
    914. memset(buff, '\0', 128);
    915. i = 0;
    916. }
    917. ch = in.get();
    918. }
    919. s += buff;
    920. return in;
    921. }
    922. //getline
    923. }
    924. //类型转换函数
    925. //atoi C
    926. //itoa C
    927. //stoi C++11
    928. //to_string

    (2)test.cpp:

    1. #include "string.h"
    2. //1.基本初始化测试
    3. void TestString1()
    4. {
    5. my::string s1("hello,world");
    6. cout << s1.c_str() << endl;
    7. //修改测试
    8. s1[0] = 'x'; //s1.operator[](0)='x';
    9. cout << s1.c_str() << endl;
    10. //读取测试
    11. for (size_t i = 0; i < s1.size(); ++i)
    12. {
    13. cout << s1[i] << " ";
    14. }
    15. cout << endl;
    16. }
    17. //2.浅拷贝及其问题测试
    18. void TestString2()
    19. {
    20. //浅拷贝带来的问题:
    21. //1.析构两次,程序崩溃 2.修改一个值,另一个也被改变
    22. my::string s1("hello,world");
    23. my::string s2(s1); //调用拷贝构造函数
    24. cout << s1.c_str() << endl;
    25. cout << s2.c_str() << endl;
    26. }
    27. //3.深拷贝测试
    28. void TestString3()
    29. {
    30. //深拷贝:使得值相同,空间大小相同,但空间地址不同
    31. my::string s1("hello,world");
    32. my::string s2(s1); //调用深拷贝构造函数
    33. cout << s1.c_str() << endl;
    34. cout << s2.c_str() << endl;
    35. s1[0] = 'x';
    36. cout << s1.c_str() << endl;
    37. cout << s2.c_str() << endl;
    38. }
    39. //4.赋值重载测试
    40. void TestString4()
    41. {
    42. //赋值面临的问题与浅拷贝相似
    43. my::string s1("hello,world");
    44. my::string s2(s1); //调用深拷贝构造函数
    45. my::string s3("qqqqqqqqqq");
    46. s1 = s3; //赋值
    47. cout << s1.c_str() << endl;
    48. cout << s2.c_str() << endl;
    49. cout << s3.c_str() << endl;
    50. }
    51. //int main()
    52. //{
    53. // //TestString1();
    54. // //TestString2();
    55. // //TestString3();
    56. // TestString4();
    57. // //对于new的异常捕获
    58. // try
    59. // {
    60. // TestString4();
    61. // }
    62. // catch (const exception& e)
    63. // {
    64. // cout << e.what() << endl;
    65. // }
    66. // return 0;
    67. //}
    68. //5.增删查改测试
    69. void TestString5()
    70. {
    71. my::string s1("hello,world");
    72. cout << s1.c_str() << endl;
    73. my::string s2;
    74. cout << s2.c_str() << endl;
    75. }
    76. //6.尾插测试+扩容测试
    77. void TestString6()
    78. {
    79. //my::string s1("hello,world");
    80. //cout << s1.c_str() << endl;
    81. 使用push_back
    82. //s1.push_back('y');
    83. //cout << s1.c_str() << endl;
    84. //s1.push_back('y');
    85. //cout << s1.c_str() << endl;
    86. 使用重载+= (附用push_back)
    87. //s1 += '6';
    88. //s1 += '7';
    89. //s1 += '8';
    90. //cout << s1.c_str() << endl;
    91. 使用重载+= (附用reserve)
    92. //s1 += 'a';
    93. //s1 += 'b';
    94. //s1 += 'c';
    95. //cout << s1.c_str() << endl;
    96. //my::string s2; //reserve解决空串_capacity=0,再去_capacity*2仍为0
    97. //s2.reserve(20); //直接开辟指定空间
    98. //库里的string::resize
    99. std::string s3("cplusplus");
    100. s3.resize(20, 'x');
    101. s3.resize(5, 'x');
    102. cout << s3 << endl;
    103. //模拟实现的string::resize
    104. my::string s4("stringtest");
    105. s4.resize(5, 'y');
    106. s4.resize(15, 'g');
    107. cout << s4.c_str() << endl;
    108. }
    109. //7.遍历测试
    110. void TestString7()
    111. {
    112. my::string s1("hello,world");
    113. //方式1:下标+[]
    114. for (size_t i = 0; i < s1.size(); ++i)
    115. {
    116. s1[i] += 1;
    117. cout << s1[i] << " ";
    118. }
    119. cout << endl;
    120. //方式2:迭代器
    121. my::string::iterator it = s1.begin();
    122. while (it != s1.end())
    123. {
    124. *it -= 1;
    125. cout << *it << " ";
    126. ++it;
    127. }
    128. cout << endl;
    129. //方式3:范围for——底层被替换成迭代器访问
    130. for (auto& ch : s1)
    131. {
    132. cout << ch << " ";
    133. ch += 1;
    134. }
    135. cout << endl;
    136. for (auto ch : s1)
    137. {
    138. cout << ch << " ";
    139. }
    140. cout << endl;
    141. }
    142. //const对象权限测试
    143. void func(const my::string& s) //string的拷贝是深拷贝,使用引用减少拷贝
    144. {
    145. //方式1:下标+[]
    146. for (size_t i = 0; i < s.size(); ++i)
    147. {
    148. //s[i] += 1; //这里传给const形参,不能写
    149. cout << s[i] << " ";
    150. }
    151. cout << endl;
    152. //方式2:迭代器
    153. my::string::const_iterator it = s.begin();
    154. while (it != s.end())
    155. {
    156. //*it -= 1; //这里调用的是const_iterator,不支持写
    157. cout << *it << " ";
    158. ++it;
    159. }
    160. cout << endl;
    161. //方式3:范围for——底层被替换成迭代器访问
    162. for (auto& ch : s) //s是const修饰,会调用对应的迭代器
    163. {
    164. //cout << ch << " ";
    165. //ch += 1; //这里调用的是const_iterator,不支持写
    166. cout << ch << " ";
    167. }
    168. cout << endl;
    169. }
    170. //8.insert测试
    171. void TestString8()
    172. {
    173. my::string s1("hello,world");
    174. //插入字符
    175. //s1.insert(6, '@');
    176. //cout << s1.c_str() << endl;
    177. //s1 += '#';
    178. //cout << s1.c_str() << endl;
    179. 遍历:范围for,按照实际长度去遍历
    180. //for (auto& ch : s1)
    181. //{
    182. // cout << ch << " ";
    183. //}
    184. //cout << endl;
    185. //s1 += '\0'; //无法打印,不可见字符,使用范围for可确定,但不显示
    186. //cout << s1.c_str() << endl;
    187. //s1 += '&';
    188. //cout << s1.c_str() << endl;
    189. 遍历:范围for,按照实际长度去遍历
    190. //for (auto& ch : s1)
    191. //{
    192. // cout << ch << " ";
    193. //}
    194. //cout << endl;
    195. //s1.insert(0, '#');
    196. //cout << s1.c_str() << endl;
    197. //插入字符串
    198. s1.insert(0, "###");
    199. cout << s1.c_str() << endl;
    200. s1.insert(10, "@@@");
    201. cout << s1.c_str() << endl;
    202. }
    203. //9.erase测试
    204. void TestString9()
    205. {
    206. my::string s1("hello,world");
    207. cout << s1.c_str() << endl;
    208. //删除字符串
    209. s1.erase(0, 3);
    210. cout << s1.c_str() << endl;
    211. s1.erase(5, 10);
    212. cout << s1.c_str() << endl;
    213. s1.erase(1); //位置1之后全删完
    214. cout << s1.c_str() << endl;
    215. }
    216. //10.find测试
    217. void TestString10()
    218. {
    219. my::string s1("hello,world");
    220. cout << s1.c_str() << endl;
    221. //查找字符
    222. size_t found = s1.find('w');
    223. cout << "Object found at : "<
    224. //查找字符
    225. found = s1.find('l');
    226. cout << "Object found at : " << found << endl;
    227. //查找字符串
    228. found = s1.find("hell");
    229. cout << "Object found at : " << found << endl;
    230. }
    231. //11.流重载测试
    232. void TestString11()
    233. {
    234. //1.<< 测试
    235. //my::string s1("hello,world");
    236. //cout << s1.c_str() << endl;
    237. //s1 += 'x';
    238. //cout << s1 << endl;
    239. //s1 += '\0';
    240. //s1 += '@';
    241. //cout << s1 << endl;
    242. //cout << s1.c_str() << endl; //读取到\0就结束
    243. //2.>>测试
    244. /*my::string s2,s3;
    245. cin >> s2>>s3;
    246. cout << s2 << endl;
    247. cout << s3 << endl;*/
    248. my::string s4("hello,world");
    249. cin >> s4;
    250. cout << s4 << endl;
    251. }
    252. //12.赋值重载测试
    253. void TestString12()
    254. {
    255. my::string s1("hello,world");
    256. my::string s2(s1);
    257. cout << s2<< endl;
    258. my::string s3;
    259. s3 = s1;
    260. cout << s3 << endl;
    261. }
    262. //13.转换函数测试
    263. void TestString13()
    264. {
    265. int i;
    266. cin >> i;
    267. string s1 = to_string(i); //to_string是库里的
    268. cout << s1 << endl;
    269. int val = stoi(s1); //stoi是库里的
    270. cout << s1 << endl;
    271. }
    272. int main()
    273. {
    274. //TestString1();
    275. //TestString2();
    276. //TestString3();
    277. //TestString4();
    278. //TestString5();
    279. //TestString6();
    280. //TestString7();
    281. //func("hello,world");
    282. //TestString8();
    283. //TestString9();
    284. //TestString10();
    285. //TestString11();
    286. //TestString12();
    287. TestString13();
    288. //对于new的异常捕获
    289. /*try
    290. {
    291. TestString4();
    292. }
    293. catch (const exception& e)
    294. {
    295. cout << e.what() << endl;
    296. }*/
    297. return 0;
    298. }

    后记:
    ●由于作者水平有限,文章难免存在谬误之处,敬请读者斧正,俚语成篇,恳望指教!
                                                                        ——By 作者:新晓·故知 

  • 相关阅读:
    每日一题 LCP 06. 拿硬币
    求求了!这份GitHub 70K+的纯手写RabbitMQ 笔记都给我码住好吗!
    Python练习题:实现除自身以外元素的乘积
    论文解读:《DeepIPs:使用基于深度学习的方法对SARS-CoV-2感染的磷酸化位点进行全面评估和计算识别》
    Vue-router的安装使用
    Rocky/GNU之Zabbix部署(1)
    CDH/CDP中开启kerberos后如何访问HDFS/YARN/HIVESERVER2 等服务的webui
    Oracle中序列
    做测试8年,33岁前只想追求大厂高薪,今年只求稳定收入
    SMART S7-200PLC控制步进电机转动 step7开发环境 步进电机选择
  • 原文地址:https://blog.csdn.net/m0_57859086/article/details/126124276