• string类


    1. 为什么学习string类?

          C 语言中,字符串是以 '\0' 结尾的一些字符的集合,为了操作方便, C 标准库中提供了一些 str 系列的库函数, 但是这些库函数与字符串是分离开的,不太符合OOP 的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。

    2. 标准库中的string类

    2.1 string

    1. 字符串是表示字符序列的类 。
    2. 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性。
    3. string 类是使用 char( 即作为它的字符类型,使用它的默认 char_traits 和分配器类型。
    4. string 类是 basic_string 模板类的一个实例,它使用 char 来实例化 basic_string 模板类,并用 char_traits 和allocator 作为 basic_string 的默认参数。
    5. 注意,这个类独立于所使用的编码来处理字节 : 如果用来处理多字节或变长字符 ( UTF-8) 的序列,这个类的所有成员( 如长度或大小 ) 以及它的迭代器,将仍然按照字节 ( 而不是实际编码的字符 ) 来操作。

    总结: 

    • string是表示字符串的字符串类。
    • 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
    • string 在底层实际是: basic_string 模板类的别名, typedef basic_string string;
    • 不能操作多字节或者变长字符的序列。

       使用string类时,必须包含#include头文件以及using namespace std;

    2.2 string类的常用接口说明

    1. string类对象的常见构造

    (constructor)函数名称
    功能说明
    string( ) 
    构造空的string类对象,即空字符串
    string(const char* s)
    用C-string来构造string类对象
    string(size_t n, char c)
    string类对象中包含n个字符c
    string(const string&s)
    拷贝构造函数
    1. void Teststring()
    2. {
    3. string s1; // 构造空的string类对象s1
    4. string s2("hello China"); // 用C格式字符串构造string类对象s2
    5. string s3(s2); // 拷贝构造s3
    6. }

    2. string类对象的容量操作

    函数名称
    功能说明
    size
    返回字符串有效字符长度
    length
    返回字符串有效字符长度
    capacity
    返回空间总大小
    empty
    检测字符串释放为空串,是返回true,否则返回false
    clear
    清空有效字符
    reserve
    为字符串预留空间**
    resize
    将有效字符的个数该成n个,多出的空间用字符c填充
    注意:
    1. 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. string类对象的访问及遍历操作

    函数名称
    功能说明
    operator[ ]
    返回pos位置的字符,const string类对象调用
    begin+end
    begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器
    rbegin+rend
    begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器
    范围for
    C++11支持更简洁的范围for的新遍历方式

     4.string类对象的修改操作

    函数名称功能说明
    push_back
    在字符串后尾插字符 c
    append
    在字符串后追加一个字符串
    operator+=
    在字符串后追加字符串 str
    c_str
    返回 C 格式字符串
    find + npos
    从字符串 pos 位置开始往后找字符 c ,返回该字符在字符串中的位置
    rfind
    从字符串 pos 位置开始往前找字符 c ,返回该字符在字符串中的位置
    substr
    str 中从 pos 位置开始,截取 n 个字符,然后将其返回
    注意:
    1. string 尾部追加字符时, s.push_back(c) / s.append(1, c) / s += 'c' 三种的实现方式差不多,一般情况下string 类的 += 操作用的比较多, += 操作不仅可以连接单个字符,还可以连接字符串。
    2. string 操作时,如果能够大概预估到放多少字符,可以先通过 reserve 把空间预留好。

    5. string类非成员函数

    函数
    功能说明
    operator+
    尽量少用,因为传值返回,导致深拷贝效率低
    operator>>
    输入运算符重载
    operator<<
    输出运算符重载
    getline
    获取一行字符串
    relational operators 
    大小比较

    3.总结

    1. //string.h
    2. #pragma once
    3. namespace bit
    4. {
    5. class string
    6. {
    7. public:
    8. typedef char* iterator;
    9. typedef const char* const_iterator;
    10. iterator begin()
    11. {
    12. return _str;
    13. }
    14. iterator end()
    15. {
    16. return _str + _size;
    17. }
    18. const_iterator begin() const
    19. {
    20. return _str;
    21. }
    22. const_iterator end() const
    23. {
    24. return _str + _size;
    25. }
    26. /*string()
    27. :_str(new char[1])
    28. , _size(0)
    29. , _capacity(0)
    30. {
    31. _str[0] = '\0';
    32. }*/
    33. // 不能这么初始化空对象
    34. /*string()
    35. :_str(nullptr)
    36. , _size(0)
    37. , _capacity(0)
    38. {}*/
    39. //string(const char* str = "\0")
    40. /*string(const char* str = "")
    41. :_str(new char[strlen(str)+1])
    42. , _size(strlen(str))
    43. , _capacity(strlen(str))
    44. {
    45. strcpy(_str, str);
    46. }*/
    47. /* string(const char* str = "")
    48. : _size(strlen(str))
    49. , _capacity(_size)
    50. , _str(new char[_capacity + 1])
    51. {
    52. strcpy(_str, str);
    53. }*/
    54. string(const char* str = "")
    55. {
    56. _size = strlen(str);
    57. _capacity = _size;
    58. _str = new char[_capacity + 1];
    59. strcpy(_str, str);
    60. }
    61. // 传统写法
    62. // s2(s1)
    63. //string(const string& s)
    64. // :_str(new char[s._capacity+1])
    65. // , _size(s._size)
    66. // , _capacity(s._capacity)
    67. //{
    68. // strcpy(_str, s._str);
    69. //}
    70. s1 = s3
    71. s1 = s1
    72. //string& operator=(const string& s)
    73. //{
    74. // if (this != &s)
    75. // {
    76. // char* tmp = new char[s._capacity + 1];
    77. // strcpy(tmp, s._str);
    78. // delete[] _str;
    79. // _str = tmp;
    80. // _size = s._size;
    81. // _capacity = s._capacity;
    82. // }
    83. // return *this;
    84. //}
    85. // 现代写法 -- 资本主义/老板思维
    86. // s2(s1)
    87. void swap(string& tmp)
    88. {
    89. ::swap(_str, tmp._str);
    90. ::swap(_size, tmp._size);
    91. ::swap(_capacity, tmp._capacity);
    92. }
    93. // s2(s1)
    94. string(const string& s)
    95. :_str(nullptr)
    96. , _size(0)
    97. , _capacity(0)
    98. {
    99. string tmp(s._str);
    100. swap(tmp); //this->swap(tmp);
    101. }
    102. // s1 = s3
    103. //string& operator=(const string& s)
    104. //{
    105. // if (this != &s)
    106. // {
    107. // //string tmp(s._str);
    108. // string tmp(s);
    109. // swap(tmp); // this->swap(tmp);
    110. // }
    111. // return *this;
    112. //}
    113. // s1 = s3
    114. // s顶替tmp做打工人
    115. string& operator=(string s)
    116. {
    117. swap(s);
    118. return *this;
    119. }
    120. ~string()
    121. {
    122. delete[] _str;
    123. _str = nullptr;
    124. _size = _capacity = 0;
    125. }
    126. const char* c_str() const
    127. {
    128. return _str;
    129. }
    130. size_t size() const
    131. {
    132. return _size;
    133. }
    134. size_t capacity() const
    135. {
    136. return _capacity;
    137. }
    138. const char& operator[](size_t pos) const
    139. {
    140. assert(pos < _size);
    141. return _str[pos];
    142. }
    143. char& operator[](size_t pos)
    144. {
    145. assert(pos < _size);
    146. return _str[pos];
    147. }
    148. void reserve(size_t n)
    149. {
    150. if (n > _capacity)
    151. {
    152. char* tmp = new char[n + 1];
    153. strcpy(tmp, _str);
    154. delete[] _str;
    155. _str = tmp;
    156. _capacity = n;
    157. }
    158. }
    159. void resize(size_t n, char ch = '\0')
    160. {
    161. if (n > _size)
    162. {
    163. // 插入数据
    164. reserve(n);
    165. for (size_t i = _size; i < n; ++i)
    166. {
    167. _str[i] = ch;
    168. }
    169. _str[n] = '\0';
    170. _size = n;
    171. }
    172. else
    173. {
    174. // 删除数据
    175. _str[n] = '\0';
    176. _size = n;
    177. }
    178. }
    179. void push_back(char ch)
    180. {
    181. // 满了就扩容
    182. /*if (_size == _capacity)
    183. {
    184. reserve(_capacity == 0 ? 4 : _capacity * 2);
    185. }
    186. _str[_size] = ch;
    187. ++_size;
    188. _str[_size] = '\0';*/
    189. insert(_size, ch);
    190. }
    191. void append(const char* str)
    192. {
    193. //size_t len = strlen(str);
    194. 满了就扩容
    195. _size + len 8 18 10
    196. //if (_size + len > _capacity)
    197. //{
    198. // reserve(_size+len);
    199. //}
    200. //strcpy(_str + _size, str);
    201. strcat(_str, str); 需要找\0,效率低
    202. //_size += len;
    203. insert(_size, str);
    204. }
    205. /*void append(const string& s)
    206. {
    207. append(s._str);
    208. }
    209. void append(size_t n, char ch)
    210. {
    211. reserve(_size + n);
    212. for (size_t i = 0; i < n; ++i)
    213. {
    214. push_back(ch);
    215. }
    216. }*/
    217. string& operator+=(char ch)
    218. {
    219. push_back(ch);
    220. return *this;
    221. }
    222. string& operator+=(const char* str)
    223. {
    224. append(str);
    225. return *this;
    226. }
    227. string& insert(size_t pos, char ch)
    228. {
    229. assert(pos <= _size);
    230. // 满了就扩容
    231. if (_size == _capacity)
    232. {
    233. reserve(_capacity == 0 ? 4 : _capacity * 2);
    234. }
    235. 挪动数据
    236. //int end = _size;
    237. //while (end >= (int)pos)
    238. //{
    239. // _str[end + 1] = _str[end];
    240. // --end;
    241. //}
    242. size_t end = _size + 1;
    243. while (end > pos)
    244. {
    245. _str[end] = _str[end - 1];
    246. --end;
    247. }
    248. _str[pos] = ch;
    249. ++_size;
    250. return *this;
    251. }
    252. string& insert(size_t pos, const char* str)
    253. {
    254. assert(pos <= _size);
    255. size_t len = strlen(str);
    256. if (_size + len > _capacity)
    257. {
    258. reserve(_size + len);
    259. }
    260. // 挪动数据
    261. size_t end = _size + len;
    262. while (end >= pos + len)
    263. {
    264. _str[end] = _str[end - len];
    265. --end;
    266. }
    267. strncpy(_str + pos, str, len);
    268. _size += len;
    269. return *this;
    270. }
    271. void erase(size_t pos, size_t len = npos)
    272. {
    273. assert(pos < _size);
    274. if (len == npos || pos + len >= _size)
    275. {
    276. _str[pos] = '\0';
    277. _size = pos;
    278. }
    279. else
    280. {
    281. strcpy(_str + pos, _str + pos + len);
    282. _size -= len;
    283. }
    284. }
    285. void clear()
    286. {
    287. _str[0] = '\0';
    288. _size = 0;
    289. }
    290. size_t find(char ch, size_t pos = 0) const
    291. {
    292. assert(pos < _size);
    293. for (size_t i = pos; i < _size; ++i)
    294. {
    295. if (ch == _str[i])
    296. {
    297. return i;
    298. }
    299. }
    300. return npos;
    301. }
    302. // "hello world bit"
    303. size_t find(const char* sub, size_t pos = 0) const
    304. {
    305. assert(sub);
    306. assert(pos < _size);
    307. // kmp/bm
    308. const char* ptr = strstr(_str + pos, sub);
    309. if (ptr == nullptr)
    310. {
    311. return npos;
    312. }
    313. else
    314. {
    315. return ptr - _str;
    316. }
    317. }
    318. // "hello world bit"
    319. string substr(size_t pos, size_t len = npos) const
    320. {
    321. assert(pos < _size);
    322. size_t realLen = len;
    323. if (len == npos || pos + len > _size)
    324. {
    325. realLen = _size - pos;
    326. }
    327. string sub;
    328. for (size_t i = 0; i < realLen; ++i)
    329. {
    330. sub += _str[pos + i];
    331. }
    332. return sub;
    333. }
    334. bool operator>(const string& s) const
    335. {
    336. return strcmp(_str, s._str) > 0;
    337. }
    338. bool operator==(const string& s) const
    339. {
    340. return strcmp(_str, s._str) == 0;
    341. }
    342. bool operator>=(const string& s) const
    343. {
    344. return *this > s || *this == s;
    345. }
    346. bool operator<=(const string& s) const
    347. {
    348. return !(*this > s);
    349. }
    350. bool operator<(const string& s) const
    351. {
    352. return !(*this >= s);
    353. }
    354. bool operator!=(const string& s) const
    355. {
    356. return !(*this == s);
    357. }
    358. private:
    359. // < 16 字符串存在buff数组中
    360. // >= 16 存在)_str指向堆空间上
    361. // char _buff[16];
    362. size_t _capacity;
    363. size_t _size;
    364. char* _str;
    365. public:
    366. // const static 语法特殊处理
    367. // 直接可以当成定义初始化
    368. const static size_t npos = -1;
    369. };
    370. ostream& operator<<(ostream& out, const string& s)
    371. {
    372. for (size_t i = 0; i < s.size(); ++i)
    373. {
    374. out << s[i];
    375. }
    376. return out;
    377. }
    378. //istream& operator>>(istream& in, string& s)
    379. //{
    380. // // 输入字符串很长,不断+=,频繁扩容,效率很低
    381. // char ch;
    382. // //in >> ch;
    383. // ch = in.get();
    384. // s.reserve(128);
    385. // while (ch != ' ' && ch != '\n')
    386. // {
    387. // //size_t old = s.capacity();
    388. // s += ch;
    389. // if (s.capacity() != old)
    390. // {
    391. // cout << old << "扩容" << s.capacity() << endl;
    392. // }
    393. // ch = in.get();
    394. // }
    395. // return in;
    396. //}
    397. istream& operator>>(istream& in, string& s)
    398. {
    399. s.clear();
    400. char ch;
    401. ch = in.get();
    402. const size_t N = 32;
    403. char buff[N];
    404. size_t i = 0;
    405. while (ch != ' ' && ch != '\n')
    406. {
    407. buff[i++] = ch;
    408. if (i == N - 1)
    409. {
    410. buff[i] = '\0';
    411. s += buff;
    412. i = 0;
    413. }
    414. ch = in.get();
    415. }
    416. buff[i] = '\0';
    417. s += buff;
    418. return in;
    419. }
    420. //size_t string::npos = -1;
    421. void test_string1()
    422. {
    423. /*std::string s1("hello world");
    424. std::string s2;*/
    425. string s1("hello world");
    426. string s2;
    427. cout << s1.c_str() << endl;
    428. cout << s2.c_str() << endl;
    429. for (size_t i = 0; i < s1.size(); ++i)
    430. {
    431. cout << s1[i] << " ";
    432. }
    433. cout << endl;
    434. for (size_t i = 0; i < s1.size(); ++i)
    435. {
    436. s1[i]++;
    437. }
    438. for (size_t i = 0; i < s1.size(); ++i)
    439. {
    440. cout << s1[i] << " ";
    441. }
    442. cout << endl;
    443. }
    444. void test_string2()
    445. {
    446. string s1("hello world");
    447. string::iterator it = s1.begin();
    448. while (it != s1.end())
    449. {
    450. cout << *it << " ";
    451. ++it;
    452. }
    453. cout << endl;
    454. it = s1.begin();
    455. while (it != s1.end())
    456. {
    457. *it += 1;
    458. ++it;
    459. }
    460. cout << endl;
    461. for (auto ch : s1)
    462. {
    463. cout << ch << " ";
    464. }
    465. cout << endl;
    466. }
    467. void test_string3()
    468. {
    469. string s1("hello world");
    470. string s2(s1);
    471. cout << s1.c_str() << endl;
    472. cout << s2.c_str() << endl;
    473. s2[0] = 'x';
    474. cout << s1.c_str() << endl;
    475. cout << s2.c_str() << endl;
    476. string s3("111111111111111111111111111111");
    477. s1 = s3;
    478. cout << s1.c_str() << endl;
    479. cout << s3.c_str() << endl;
    480. s1 = s1;
    481. cout << s1.c_str() << endl;
    482. cout << s3.c_str() << endl;
    483. }
    484. void test_string4()
    485. {
    486. string s1("hello world");
    487. string s2("xxxxxxx");
    488. s1.swap(s2);
    489. swap(s1, s2);
    490. }
    491. void test_string5()
    492. {
    493. string s1("hello");
    494. cout << s1.c_str() << endl;
    495. s1.push_back('x');
    496. cout << s1.c_str() << endl;
    497. cout << s1.capacity() << endl;
    498. s1 += 'y';
    499. s1 += 'z';
    500. s1 += 'z';
    501. s1 += 'z';
    502. s1 += 'z';
    503. s1 += 'z';
    504. s1 += 'z';
    505. cout << s1.c_str() << endl;
    506. cout << s1.capacity() << endl;
    507. }
    508. void test_string6()
    509. {
    510. string s1("hello");
    511. cout << s1.c_str() << endl;
    512. s1 += ' ';
    513. s1.append("world");
    514. s1 += "bit hello";
    515. cout << s1.c_str() << endl;
    516. s1.insert(5, '#');
    517. cout << s1.c_str() << endl;
    518. s1.insert(0, '#');
    519. cout << s1.c_str() << endl;
    520. }
    521. void test_string7()
    522. {
    523. string s1("hello");
    524. cout << s1.c_str() << endl;
    525. s1.insert(2, "world");
    526. cout << s1.c_str() << endl;
    527. s1.insert(0, "world ");
    528. cout << s1.c_str() << endl;
    529. }
    530. void test_string8()
    531. {
    532. string s1("hello");
    533. s1.erase(1, 10);
    534. cout << s1.c_str() << endl;
    535. string s2("hello");
    536. s2.erase(1);
    537. cout << s2.c_str() << endl;
    538. string s3("hello");
    539. s3.erase(1, 2);
    540. cout << s3.c_str() << endl;
    541. }
    542. void test_string9()
    543. {
    544. /* string s1;
    545. cin >> s1;
    546. cout << s1 << endl;*/
    547. string s1("hello");
    548. cout << s1 << endl; // operator<<(cout, s1)
    549. cout << s1.c_str() << endl;
    550. s1 += '\0';
    551. s1 += "world";
    552. cout << s1 << endl;
    553. cout << s1.c_str() << endl;
    554. string s3("hello"), s4;
    555. cin >> s3 >> s4;
    556. cout << s3 << "---" << s4 << endl;
    557. }
    558. void DealUrl(const string& url)
    559. {
    560. size_t pos1 = url.find("://");
    561. if (pos1 == string::npos)
    562. {
    563. cout << "非法url" << endl;
    564. return;
    565. }
    566. string protocol = url.substr(0, pos1);
    567. cout << protocol << endl;
    568. size_t pos2 = url.find('/', pos1 + 3);
    569. if (pos2 == string::npos)
    570. {
    571. cout << "非法url" << endl;
    572. return;
    573. }
    574. string domain = url.substr(pos1 + 3, pos2 - pos1 - 3);
    575. cout << domain << endl;
    576. string uri = url.substr(pos2 + 1);
    577. cout << uri << endl << endl;
    578. }
    579. void test_string10()
    580. {
    581. string url1 = "https://cplusplus.com/reference/string/string/";
    582. string url2 = "https://image.baidu.com/search/detail?ct=503316480&z=0&ipn=d&word=ascall&step_word=&hs=0&pn=0&spn=0&di=7108135681917976577&pi=0&rn=1&tn=baiduimagedetail&is=0%2C0&istype=0&ie=utf-8&oe=utf-8&in=&cl=2&lm=-1&st=undefined&cs=2613959014%2C543572025&os=2740573600%2C1059518451&simid=2613959014%2C543572025&adpicid=0&lpn=0&ln=179&fr=&fmq=1660115697093_R&fm=&ic=undefined&s=undefined&hd=undefined&latest=undefined©right=undefined&se=&sme=&tab=0&width=undefined&height=undefined&face=undefined&ist=&jit=&cg=&bdtype=0&oriquery=&objurl=https%3A%2F%2Fgimg2.baidu.com%2Fimage_search%2Fsrc%3Dhttp%3A%2F%2Fimg.php.cn%2Fupload%2Fimage%2F147%2F157%2F796%2F1593765739620093.png%26refer%3Dhttp%3A%2F%2Fimg.php.cn%26app%3D2002%26size%3Df9999%2C10000%26q%3Da80%26n%3D0%26g%3D0n%26fmt%3Dauto%3Fsec%3D1662707704%26t%3Da68cb238bbb3f99d0554098c785d526e&fromurl=ippr_z2C%24qAzdH3FAzdH3Fooo_z%26e3Brir_z%26e3BvgAzdH3FuwqAzdH3F9c9amd_z%26e3Bip4s&gsm=1&rpstart=0&rpnum=0&islist=&querylist=&nojc=undefined&dyTabStr=MCwzLDIsNCw2LDEsNSw3LDgsOQ%3D%3D";
    583. string url3 = "ftp://ftp.cs.umd.edu/pub/skipLists/skiplists.pdf";
    584. DealUrl(url1);
    585. DealUrl(url2);
    586. DealUrl(url3);
    587. }
    588. void test_string11()
    589. {
    590. string s1;
    591. s1.resize(20);
    592. string s2("hello");
    593. s2.resize(20, 'x');
    594. s2.resize(10);
    595. }
    596. }
    1. //Test.cpp
    2. #include
    3. #include
    4. #include
    5. #include
    6. using namespace std;
    7. void test_string1()
    8. {
    9. string s1;
    10. //string s2("hello world!!!");
    11. // string (const char* s);
    12. string s2 = "hello world!!!";
    13. cout << s1 << endl;
    14. cout << s2 << endl;
    15. string s3(s2);
    16. cout << s3 << endl;
    17. string s4(s2, 6, 5);
    18. cout << s4 << endl;
    19. // 第三个参数len大于后面字符长度,有多少拷贝多少拷贝到结尾
    20. string s5(s2, 6, 15);
    21. cout << s5 << endl;
    22. string s6(s2, 6);
    23. cout << s6 << endl;
    24. string s7("hello world", 5);
    25. cout << s7 << endl;
    26. string s8(100, 'x');
    27. cout << s8 << endl;
    28. //cin >> s1 >> s2;
    29. //cout << s1 << endl;
    30. //cout << s2 << endl;
    31. }
    32. void test_string2()
    33. {
    34. string s1;
    35. string s2 = "hello world!!!"; // 构造+拷贝构造 -》优化 -- 直接构造
    36. s1 = s2;
    37. s1 = "xxxx"; // =
    38. s1 = 'y';
    39. }
    40. void test_string3()
    41. {
    42. string s1("hello world");
    43. cout << s1[0] << endl;
    44. s1[0] = 'x';
    45. cout << s1[0] << endl;
    46. cout << s1 << endl;
    47. // 要求遍历string,每个字符+1
    48. for (size_t i = 0; i < s1.size(); ++i)
    49. //for (size_t i = 0; i < s1.length(); ++i)
    50. {
    51. s1[i]++;
    52. }
    53. cout << s1 << endl;
    54. const string s2("world");
    55. for (size_t i = 0; i < s2.size(); ++i)
    56. {
    57. //s2[i]++;
    58. cout << s2[i] << " ";
    59. }
    60. cout << endl;
    61. cout << s2 << endl;
    62. //s2[6]; 内部会检查越界
    63. }
    64. void test_string4()
    65. {
    66. string s("hello");
    67. string::iterator it = s.begin();
    68. while (it != s.end())
    69. {
    70. (*it)++;
    71. cout << *it << " ";
    72. ++it;
    73. }
    74. cout << endl;
    75. // 范围for -- 自动迭代,自动判断结束
    76. // 依次取s中每个字符,赋值给ch
    77. /*for (auto ch : s)
    78. {
    79. ch++;
    80. cout << ch << " ";
    81. }*/
    82. for (auto& ch : s)
    83. {
    84. ch++;
    85. cout << ch << " ";
    86. }
    87. cout << endl;
    88. cout << s << endl;
    89. list<int> lt(10, 1);
    90. list<int>::iterator lit = lt.begin();
    91. while (lit != lt.end())
    92. {
    93. cout << *lit << " ";
    94. ++lit;
    95. }
    96. cout << endl;
    97. for (auto e : lt)
    98. {
    99. cout << e << " ";
    100. }
    101. cout << endl;
    102. // 范围for底层其实就是迭代器
    103. }
    104. void PrintString(const string& str)
    105. {
    106. //string::const_iterator it = str.begin();
    107. auto it = str.begin();
    108. while (it != str.end())
    109. {
    110. //*it = 'x';
    111. cout << *it << " ";
    112. ++it;
    113. }
    114. cout << endl;
    115. //auto rit = str.begin();
    116. string::const_reverse_iterator rit = str.rbegin();
    117. while (rit != str.rend())
    118. {
    119. cout << *rit << " ";
    120. ++rit;
    121. }
    122. cout << endl;
    123. }
    124. // iterator/const_iterator
    125. // reverse_iterator/const_reverse_iterator
    126. void test_string5()
    127. {
    128. string s("hello");
    129. string::reverse_iterator rit = s.rbegin();
    130. while (rit != s.rend())
    131. {
    132. cout << *rit << " ";
    133. ++rit;
    134. }
    135. cout << endl;
    136. PrintString(s);
    137. }
    138. void test_string6()
    139. {
    140. string s("hello");
    141. s.push_back('-');
    142. s.push_back('-');
    143. s.append("world");
    144. cout << s << endl;
    145. string str("我来了");
    146. s += '@';
    147. s += str;
    148. s += "!!!";
    149. cout << s << endl;
    150. s.append(++str.begin(), --str.end());
    151. cout << s << endl;
    152. //string copy(++s.begin(), --s.end());
    153. string copy(s.begin() + 5, s.end() - 5);
    154. cout << copy << endl;
    155. }
    156. void test_string7()
    157. {
    158. /*string s1;
    159. string s2("11111111111111");
    160. cout << s1.max_size() << endl;
    161. cout << s2.max_size() << endl;
    162. cout << s2.capacity() << endl;
    163. cout << s2.capacity() << endl;*/
    164. string s;
    165. // reverse 逆置
    166. s.reserve(1000); //保留 开空间
    167. //s.resize(1000, 'x'); // 开空间 + 初始化
    168. size_t sz = s.capacity();
    169. sz = s.capacity();
    170. cout << "capacity changed: " << sz << '\n';
    171. cout << "making s grow:\n";
    172. for (int i = 0; i < 1000; ++i)
    173. {
    174. s.push_back('c');
    175. if (sz != s.capacity())
    176. {
    177. sz = s.capacity();
    178. cout << "capacity changed: " << sz << '\n';
    179. }
    180. }
    181. }
    182. void test_string8()
    183. {
    184. string str("wo lai le");
    185. /*for (size_t i = 0; i < str.size();)
    186. {
    187. if (str[i] == ' ')
    188. {
    189. str.insert(i, "20%");
    190. i += 4;
    191. }
    192. else
    193. {
    194. ++i;
    195. }
    196. }
    197. cout << str << endl;*/
    198. /*for (size_t i = 0; i < str.size(); ++i)
    199. {
    200. if (str[i] == ' ')
    201. {
    202. str.insert(i, "20%");
    203. i += 3;
    204. }
    205. }
    206. cout << str << endl;
    207. for (size_t i = 0; i < str.size(); ++i)
    208. {
    209. if (str[i] == ' ')
    210. {
    211. str.erase(i, 1);
    212. }
    213. }
    214. cout << str << endl;*/
    215. string newstr;
    216. for (size_t i = 0; i < str.size(); ++i)
    217. {
    218. if (str[i] != ' ')
    219. {
    220. newstr += str[i];
    221. }
    222. else
    223. {
    224. newstr += "20%";
    225. }
    226. }
    227. cout << newstr << endl;
    228. }
    229. void test_string9()
    230. {
    231. string filename("test.cpp");
    232. cout << filename << endl;
    233. cout << filename.c_str() << endl;
    234. FILE* fout = fopen(filename.c_str(), "r");
    235. assert(fout);
    236. char ch = fgetc(fout);
    237. while (ch != EOF)
    238. {
    239. cout << ch;
    240. ch = fgetc(fout);
    241. }
    242. }
    243. void test_string10()
    244. {
    245. string filename("test.cpp");
    246. cout << filename << endl;
    247. cout << filename.c_str() << endl;
    248. filename += '\0';
    249. filename += "string.cpp";
    250. cout << filename << endl; // string 对象size为准
    251. cout << filename.c_str() << endl; // 常量字符串对象\0
    252. cout << filename.size() << endl;
    253. string copy = filename;
    254. cout << copy << endl << endl;
    255. for (unsigned char ch = 0; ch < 128; ++ch)
    256. {
    257. cout << ch;
    258. }
    259. cout << endl;
    260. cout << "\\0" << endl;
    261. }
    262. void DealUrl(const string& url)
    263. {
    264. size_t pos1 = url.find("://");
    265. if (pos1 == string::npos)
    266. {
    267. cout << "非法url" << endl;
    268. return;
    269. }
    270. string protocol = url.substr(0, pos1);
    271. cout << protocol << endl;
    272. size_t pos2 = url.find('/', pos1 + 3);
    273. if (pos2 == string::npos)
    274. {
    275. cout << "非法url" << endl;
    276. return;
    277. }
    278. string domain = url.substr(pos1 + 3, pos2 - pos1 - 3);
    279. cout << domain << endl;
    280. string uri = url.substr(pos2 + 1);
    281. cout << uri << endl << endl;
    282. }
    283. void test_string11()
    284. {
    285. string filename("test.cpp.tar.zip");
    286. // 后缀
    287. //size_t pos = filename.find('.');
    288. size_t pos = filename.rfind('.');
    289. if (pos != string::npos)
    290. {
    291. //string suff = filename.substr(pos, filename.size() - pos);
    292. string suff = filename.substr(pos);
    293. cout << suff << endl;
    294. }
    295. string url1 = "https://cplusplus.com/reference/string/string/";
    296. string url2 = "https://image.baidu.com/search/detail?ct=503316480&z=0&ipn=d&word=ascall&step_word=&hs=0&pn=0&spn=0&di=7108135681917976577&pi=0&rn=1&tn=baiduimagedetail&is=0%2C0&istype=0&ie=utf-8&oe=utf-8&in=&cl=2&lm=-1&st=undefined&cs=2613959014%2C543572025&os=2740573600%2C1059518451&simid=2613959014%2C543572025&adpicid=0&lpn=0&ln=179&fr=&fmq=1660115697093_R&fm=&ic=undefined&s=undefined&hd=undefined&latest=undefined©right=undefined&se=&sme=&tab=0&width=undefined&height=undefined&face=undefined&ist=&jit=&cg=&bdtype=0&oriquery=&objurl=https%3A%2F%2Fgimg2.baidu.com%2Fimage_search%2Fsrc%3Dhttp%3A%2F%2Fimg.php.cn%2Fupload%2Fimage%2F147%2F157%2F796%2F1593765739620093.png%26refer%3Dhttp%3A%2F%2Fimg.php.cn%26app%3D2002%26size%3Df9999%2C10000%26q%3Da80%26n%3D0%26g%3D0n%26fmt%3Dauto%3Fsec%3D1662707704%26t%3Da68cb238bbb3f99d0554098c785d526e&fromurl=ippr_z2C%24qAzdH3FAzdH3Fooo_z%26e3Brir_z%26e3BvgAzdH3FuwqAzdH3F9c9amd_z%26e3Bip4s&gsm=1&rpstart=0&rpnum=0&islist=&querylist=&nojc=undefined&dyTabStr=MCwzLDIsNCw2LDEsNSw3LDgsOQ%3D%3D";
    297. string url3 = "ftp://ftp.cs.umd.edu/pub/skipLists/skiplists.pdf";
    298. DealUrl(url1);
    299. DealUrl(url2);
    300. DealUrl(url3);
    301. }
    302. void test_string12()
    303. {
    304. int ival;
    305. double dval;
    306. cin >> ival >> dval;
    307. string istr = to_string(ival);
    308. string dstr = to_string(dval);
    309. cout << istr << endl;
    310. cout << dstr << endl;
    311. istr = "9999";
    312. dstr = "9999.99";
    313. ival = stoi(istr);
    314. dval = stod(dstr);
    315. }
    316. void test_string13()
    317. {
    318. string s0;
    319. string s1("111111");
    320. string s2("11111111111111111111111111111111111111111");
    321. cout << sizeof(s1) << endl;
    322. cout << sizeof(s2) << endl;
    323. }
    324. #include "string.h"
    325. int main()
    326. {
    327. try
    328. {
    329. //bit::test_string11();
    330. test_string13();
    331. }
    332. catch (const exception& e)
    333. {
    334. cout << e.what() << endl;
    335. }
    336. return 0;
    337. }

     4.练习题

          1.给你一个字符串 s ,根据下述规则反转字符串:1.所有非英文字母保留在原有位置;2.所有英文字母(小写或大写)位置反转。返回反转后的 s 。

    1. class Solution
    2. {
    3. public:
    4. bool IsLetter(char ch)
    5. {
    6. if ((ch >= 'a' && ch <= 'z') ||
    7. (ch >= 'A' && ch <= 'Z'))
    8. return true;
    9. else
    10. return false;
    11. }
    12. string reverseOnlyLetters(string s)
    13. {
    14. size_t begin = 0, end = s.size() - 1;
    15. while (begin < end)
    16. {
    17. while (begin < end && !IsLetter(s[begin]))
    18. ++begin;
    19. while (begin < end && !IsLetter(s[end]))
    20. --end;
    21. swap(s[begin], s[end]);
    22. ++begin;
    23. --end;
    24. }
    25. return s;
    26. }
    27. };

         2.给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和并同样以字符串形式返回。

    1. class Solution {
    2. public:
    3. string addStrings(string num1, string num2) {
    4. int end1 = num1.size() - 1, end2 = num2.size() - 1;
    5. int next = 0;
    6. string strRet;
    7. while (end1 >= 0 || end2 >= 0)
    8. {
    9. int val1 = end1 >= 0 ? num1[end1] - '0' : 0;
    10. int val2 = end2 >= 0 ? num2[end2] - '0' : 0;
    11. int ret = val1 + val2 + next;
    12. next = ret > 9 ? 1 : 0;
    13. //头插
    14. //strRet.insert(0,1,'0'+(ret%10));
    15. // strRet.insert(strRet.begin(),'0'+(ret%10));
    16. //尾插
    17. strRet += ('0' + ret % 10);
    18. --end1;
    19. --end2;
    20. }
    21. if (next == 1)
    22. strRet += '1';
    23. //逆置
    24. reverse(strRet.begin(), strRet.end());
    25. return strRet;
    26. }
    27. };

         3.计算字符串最后一个单词的长度,单词以空格隔开,字符串长度小于5000。(注:字符串末尾不以空格为结尾) 

    1. #include
    2. #include
    3. using namespace std;
    4. int main()
    5. {
    6. string str;
    7. // cin>>str;
    8. getline(cin,str);
    9. size_t pos=str.rfind(' ');
    10. if(pos!=string::npos)
    11. {
    12. cout<size()-pos-1<
    13. }
    14. else
    15. {
    16. cout<size()<
    17. }
    18. }

         4.给定一个字符串 s ,找到 它的第一个不重复的字符,并返回它的索引 。如果不存在,则返回-1 。

    1. class Solution {
    2. public:
    3. int firstUniqChar(string s) {
    4. int countArr[26]={0};
    5. for(auto ch:s)
    6. {
    7. countArr[ch-'a']++;
    8. }
    9. for(size_t i=0;isize();i++)
    10. {
    11. if(countArr[s[i]-'a']==1)
    12. return i;
    13. }
    14. return -1;
    15. }
    16. };

         5.如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个回文串。

    1. class Solution
    2. {
    3. public:
    4. bool isLetterOrNumber(char ch)
    5. {
    6. return (ch >= '0' && ch <= '9')
    7. || (ch >= 'a' && ch <= 'z')
    8. || (ch >= 'A' && ch <= 'Z');
    9. }
    10. bool isPalindrome(string s)
    11. {
    12. // 先小写字母转换成大写,再进行判断
    13. for (auto& ch : s)
    14. {
    15. if (ch >= 'a' && ch <= 'z')
    16. ch -= 32;
    17. }
    18. int begin = 0, end = s.size() - 1;
    19. while (begin < end)
    20. {
    21. while (begin < end && !isLetterOrNumber(s[begin]))
    22. ++begin;
    23. while (begin < end && !isLetterOrNumber(s[end]))
    24. --end;
    25. if (s[begin] != s[end])
    26. {
    27. return false;
    28. }
    29. else
    30. {
    31. ++begin;
    32. --end;
    33. }
    34. }
    35. return true;
    36. }
    37. };

    5.string类的模拟实现

    5.1 浅拷贝

         浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来 。如果 对象中管理资源 ,最后就会 导致多个对象共 享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为 还有效,所以当继续对资源进项操作时,就会发生发生了访问违规

    5.2 深拷贝

         如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供。

    5.3 写时拷贝

           写时拷贝就是一种拖延症,是在浅拷贝的基础之上增加了引用计数的方式来实现的。
           引用计数:用来记录资源使用者的个数。在构造时,将资源的计数给成 1 ,每增加一个对象使用该资源,就给计数增加1 ,当某个对象被销毁时,先给该计数减 1 ,然后再检查是否需要释放资源,如果计数为 1 ,说明该对象时资源的最后一个使用者,将该资源释放;否则就不能释放,因为还有其他对象在使用该资源。
  • 相关阅读:
    项目经理必备思维之整合思维
    Git(6)——GitHub
    LeetCode算法日记:1224. 最大相等频率
    【全网唯一有效】MacOS 12.4安装Parallels Desktop 17.1.x出现网络错误等等解决
    端粒/端粒酶生信切入点,6+端粒酶+泛癌+甲基化+实验。
    JCL入门教程
    什么是JavaScript中的IIFE(Immediately Invoked Function Expression)?它的作用是什么?
    Linux系统编程-网络基础(四)-网络层-协议:IP(因特网互联协议)【IP报头大小:20字节】
    七周成为数据分析师 | 数据可视化
    elmentui表格修改可点击排序元素
  • 原文地址:https://blog.csdn.net/zhao19971014/article/details/126487786