• string类


    一、string类的介绍

    1. 字符串是表示字符序列的类

    2. 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性。

    3. string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型(关于模板的更多信息,请参阅basic_string)。

    4. string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits和allocator作为basic_string的默认参数(根于更多的模板信息请参考basic_string)。

    5. 注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作

    总结:

    1. string是表示字符串的字符串类
    2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
    3. string在底层实际是:basic_string模板类的别名,typedef basic_stringstring;
    4. 不能操作多字节或者变长字符的序列。
    在使用string类时,必须包含#include头文件以及using namespace std;
     

    二、string类的常用接口

    2.1、string类对象的常见构造

     函数名称 功能说明
    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 bit"); // 用C格式字符串构造string类对象s2
    5. string s3(s2); // 拷贝构造s3
    6. }

    2.2、string类对象的容量操作

    函数名称功能说明
    size返回字符串有效字符长度
    length返回字符串有效字符长度
    capacity返回空间总大小
    empty 检测字符串释放为空串,是返回true,否则返回false
    clear 清空有效字符
    reserve 为字符串预留空间**
    resize                     将有效字符的个数该成n个,多出的空间用字符c填充

    代码演示

    1. #define _CRT_SECURE_NO_WARNINGS
    2. #include
    3. using namespace std;
    4. #include
    5. // 测试string容量相关的接口
    6. // size/clear/resize
    7. void Teststring1()
    8. {
    9. // 注意:string类对象支持直接用cin和cout进行输入和输出
    10. string s("hello!!!");
    11. cout << s.size() << endl;
    12. cout << s.length() << endl;
    13. cout << s.capacity() << endl;
    14. cout << s << endl;
    15. // 将s中的字符串清空,注意清空时只是将size清0,不改变底层空间的大小
    16. s.clear();
    17. cout << s.size() << endl;
    18. cout << s.capacity() << endl;
    19. // 将s中有效字符个数增加到10个,多出位置用'a'进行填充
    20. // “aaaaaaaaaa”
    21. s.resize(10, 'a');
    22. cout << s.size() << endl;
    23. cout << s.capacity() << endl;
    24. // 将s中有效字符个数增加到15个,多出位置用缺省值'\0'进行填充
    25. // "aaaaaaaaaa\0\0\0\0\0"
    26. // 注意此时s中有效字符个数已经增加到15个
    27. s.resize(15);
    28. cout << s.size() << endl;
    29. cout << s.capacity() << endl;
    30. cout << s << endl;
    31. // 将s中有效字符个数缩小到5个
    32. s.resize(5);
    33. cout << s.size() << endl;
    34. cout << s.capacity() << endl;
    35. cout << s << endl;
    36. }
    37. //====================================================================================
    38. void Teststring2()
    39. {
    40. string s;
    41. // 测试reserve是否会改变string中有效元素个数
    42. s.reserve(100);
    43. cout << s.size() << endl;
    44. cout << s.capacity() << endl;
    45. // 测试reserve参数小于string的底层空间大小时,是否会将空间缩小
    46. s.reserve(50);
    47. cout << s.size() << endl;
    48. cout << s.capacity() << endl;
    49. }
    50. // 利用reserve提高插入数据的效率,避免增容带来的开销
    51. //====================================================================================
    52. void TestPushBack()
    53. {
    54. string s;
    55. size_t sz = s.capacity();
    56. cout << "making s grow:\n";
    57. for (int i = 0; i < 100; ++i)
    58. {
    59. s.push_back('c');
    60. if (sz != s.capacity())
    61. {
    62. sz = s.capacity();
    63. cout << "capacity changed: " << sz << '\n';
    64. }
    65. }
    66. }
    67. // 构建vector时,如果提前已经知道string中大概要放多少个元素,可以提前将string中空间设置好
    68. void TestPushBackReserve()
    69. {
    70. string s;
    71. s.reserve(100);
    72. size_t sz = s.capacity();
    73. cout << "making s grow:\n";
    74. for (int i = 0; i < 100; ++i)
    75. {
    76. s.push_back('c');
    77. if (sz != s.capacity())
    78. {
    79. sz = s.capacity();
    80. cout << "capacity changed: " << sz << '\n';
    81. }
    82. }
    83. }
    84. //
    85. // 测试string:
    86. // 1. 插入(拼接)方式:push_back append operator+=
    87. // 2. 正向和反向查找:find() + rfind()
    88. // 3. 截取子串:substr()
    89. // 4. 删除:erase
    90. void Teststring5()
    91. {
    92. string str;
    93. str.push_back(' '); // 在str后插入空格
    94. str.append("hello"); // 在str后追加一个字符"hello"
    95. str += 'b'; // 在str后追加一个字符'b'
    96. str += "it"; // 在str后追加一个字符串"it"
    97. cout << str << endl;
    98. cout << str.c_str() << endl; // 以C语言的方式打印字符串
    99. // 获取file的后缀
    100. string file("string.cpp");
    101. size_t pos = file.rfind('.');
    102. string suffix(file.substr(pos, file.size() - pos));
    103. cout << suffix << endl;
    104. // npos是string里面的一个静态成员变量
    105. // static const size_t npos = -1;
    106. // 取出url中的域名
    107. string url("http://www.cplusplus.com/reference/string/string/find/");
    108. cout << url << endl;
    109. size_t start = url.find("://");
    110. if (start == string::npos)
    111. {
    112. cout << "invalid url" << endl;
    113. return;
    114. }
    115. start += 3;
    116. size_t finish = url.find('/', start);
    117. string address = url.substr(start, finish - start);
    118. cout << address << endl;
    119. // 删除url的协议前缀
    120. pos = url.find("://");
    121. url.erase(0, pos + 3);
    122. cout << url << endl;
    123. }
    124. int main()
    125. {
    126. return 0;
    127. }

    注意:
    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不会改变容量大小
     

    2.3、string类对象的访问及遍历

    函数名称功能说明
    operator[]           返回pos位置的字符,const string类对象调用
    begin+ endbegin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭
    代器
    rbegin + rendbegin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭
    代器
    范围forC++11支持更简洁的范围for的新遍历方式
    1. / string的遍历
    2. // begin()+end() for+[] 范围for
    3. // 注意:string遍历时使用最多的还是for+下标 或者 范围for(C++11后才支持)
    4. // begin()+end()大多数使用在需要使用STL提供的算法操作string时,比如:采用reverse逆置string
    5. void Teststring3()
    6. {
    7. string s1("hello ");
    8. const string s2("Hello ");
    9. cout << s1 << " " << s2 << endl;
    10. cout << s1[0] << " " << s2[0] << endl;
    11. s1[0] = 'H';
    12. cout << s1 << endl;
    13. // s2[0] = 'h'; 代码编译失败,因为const类型对象不能修改
    14. }
    15. void Teststring4()
    16. {
    17. string s("hello ");
    18. // 3种遍历方式:
    19. // 需要注意的以下三种方式除了遍历string对象,还可以遍历是修改string中的字符,
    20. // 另外以下三种方式对于string而言,第一种使用最多
    21. // 1. for+operator[]
    22. for (size_t i = 0; i < s.size(); ++i)
    23. cout << s[i] << endl;
    24. // 2.迭代器
    25. string::iterator it = s.begin();
    26. while (it != s.end())
    27. {
    28. cout << *it << endl;
    29. ++it;
    30. }
    31. // string::reverse_iterator rit = s.rbegin();
    32. // C++11之后,直接使用auto定义迭代器,让编译器推到迭代器的类型
    33. auto rit = s.rbegin();
    34. while (rit != s.rend())
    35. cout << *rit << endl;
    36. // 3.范围for
    37. for (auto ch : s)
    38. cout << ch << endl;
    39. }

    2.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把空间预留好。

    2.5、string类非成员函数

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

    三、模拟实现string类

    为了防止string类和库函数重名,我们把我们的代码写在命名空间里。

    1. #pragma once
    2. #define _CRT_SECURE_NO_WARNINGS
    3. #include
    4. using namespace std;
    5. #include
    6. #include
    7. namespace LYL
    8. {
    9. class string
    10. {
    11. public:
    12. //迭代器
    13. typedef char* iterator;
    14. //const 修饰的迭代器
    15. typedef const char* const_iterator;
    16. iterator begin()
    17. {
    18. return _str;
    19. }
    20. iterator end()
    21. {
    22. return _str + _size;
    23. }
    24. const_iterator begin() const
    25. {
    26. return _str;
    27. }
    28. const_iterator end() const
    29. {
    30. return _str + _size;
    31. }
    32. //构造函数
    33. string(const char* str = "") :
    34. _size(strlen(str))
    35. {
    36. _capacity = _size == 0 ? 3 : _size;
    37. _str = new char[_capacity + 1];
    38. strcpy(_str, str);
    39. }
    40. //拷贝构造函数
    41. string(const string& s)
    42. :_size(s._size),
    43. _capacity(s._capacity)
    44. {
    45. _str = new char[s._capacity + 1];
    46. strcpy(_str, s._str);
    47. }
    48. //运算符重载
    49. //=运算符重载
    50. string& operator=(const string& s)
    51. {
    52. if (this != &s)
    53. {
    54. char* tmp = new char[s._capacity + 1];
    55. strcpy(tmp, s._str);
    56. delete[] _str;
    57. _str = tmp;
    58. _size = s._size;
    59. _capacity = s._capacity;
    60. }
    61. return *this;
    62. }
    63. //[]运算符重载
    64. char& operator[](size_t pos) const
    65. {
    66. assert(pos < _size);
    67. return _str[pos];
    68. }
    69. char& operator[](size_t pos)
    70. {
    71. assert(pos < _size);
    72. return _str[pos];
    73. }
    74. //析构函数
    75. ~string()
    76. {
    77. _capacity = 0;
    78. _size = 0;
    79. delete[] _str;
    80. _str = nullptr;
    81. }
    82. // 不修改成员变量数据的函数,最好都加上const
    83. //函数c_str的实现
    84. const char* c_str()
    85. {
    86. return _str;
    87. }
    88. //size()函数实现
    89. size_t size() const
    90. {
    91. return _size;
    92. }
    93. //capacity()函数实现
    94. size_t capacity() const
    95. {
    96. return _capacity;
    97. }
    98. bool operator>(const string& s) const
    99. {
    100. return strcmp(s._str, this->_str) > 0;
    101. }
    102. bool operator==(const string& s)
    103. {
    104. return strcmp(s._str, _str) == 0;
    105. }
    106. bool operator>=(const string& s)
    107. {
    108. return _str > s._str || _str == s._str;
    109. //return *this > s || *s == this; 这里如果没有用const修饰函数,*this和s的位置就不可以改变,改变了就是权限放大。
    110. }
    111. bool operator<(const string& s)
    112. {
    113. return !(*this >= s);
    114. }
    115. bool operator<=(const string& s)
    116. {
    117. return !(*this > s);
    118. }
    119. bool operator!=(const string& s)
    120. {
    121. return !(*this == s);
    122. }
    123. //reserve函数实现(开辟空间)
    124. void reserve(size_t n)
    125. {
    126. if (n > _capacity)
    127. {
    128. //扩容
    129. char* tmp = new char[n + 1];
    130. strcpy(tmp, _str);
    131. delete[] _str;
    132. _str = tmp;
    133. _capacity = n;
    134. }
    135. }
    136. //resize函数实现(开除的空间并初始化)
    137. void resize(size_t n, char ch = '\0')
    138. {
    139. if (_size >= n)
    140. {
    141. //删除数据----保留前n个数据
    142. _size = n;
    143. _str[_size] = '\0';
    144. }
    145. else
    146. {
    147. if (_capacity < n)
    148. {
    149. //空间不够先扩容
    150. reserve(n);
    151. }
    152. size_t i = _size;
    153. while (i < n)
    154. {
    155. _str[i] = ch;
    156. i++;
    157. }
    158. _size = n;
    159. _str[_size] = '\0';
    160. }
    161. }
    162. //push_back函数实现
    163. //在字符串后添加一个字符
    164. void push_back(char ch)
    165. {
    166. if (_size + 1 > _capacity)
    167. {
    168. reserve(_capacity * 2);
    169. }
    170. _str[_size] = ch;
    171. _str[_size++] = '\0';
    172. }
    173. //qppend函数实现
    174. //在字符串后添加一个字符串
    175. void append(const char* str)
    176. {
    177. size_t len = strlen(str);
    178. if (_size + len > _capacity)
    179. {
    180. reserve(_capacity + len);
    181. }
    182. strcpy(_str + _size, str);
    183. _size += len;
    184. }
    185. string& operator+=(char ch)
    186. {
    187. push_back(ch);
    188. return *this;
    189. }
    190. string& operator+=(const char* str)
    191. {
    192. append(str);
    193. return *this;
    194. }
    195. //insert函数实现
    196. //函数重载,一个插入字符,一个插入字符串
    197. string& insert(size_t pos, char ch)
    198. {
    199. assert(pos <= _size);
    200. if (_size + 1 > _capacity)
    201. {
    202. reserve(2 * _capacity);
    203. }
    204. size_t end = _size + 1;
    205. while (end > pos)
    206. {
    207. _str[end] = _str[end - 1];
    208. end--;
    209. }
    210. _str[pos] = ch;
    211. _size += 1;
    212. return *this;
    213. }
    214. string& insert(size_t pos, const char* str)
    215. {
    216. assert(pos <= _size);
    217. size_t len = strlen(str);
    218. if (_size + len > _capacity)
    219. {
    220. reserve(_size + len);
    221. }
    222. //挪动数据
    223. size_t end = _size + len;
    224. while (end > pos + len - 1)
    225. {
    226. _str[end - pos] = _str[end];
    227. end--;
    228. }
    229. //拷贝数据
    230. strncpy(_str + pos, str, len);
    231. _size += len;
    232. return *this;
    233. }
    234. //erase函数实现
    235. string& erase(size_t pos, size_t len = npos)
    236. {
    237. assert(pos < _size);
    238. if (len == npos || pos + len >= _size)
    239. {
    240. _str[pos] = '\0';
    241. _size = pos;
    242. }
    243. else
    244. {
    245. strcpy(_str + pos, _str + pos + len);
    246. _size -= len;
    247. }
    248. return *this;
    249. }
    250. //swap函数实现
    251. void swap(string& s)
    252. {
    253. std::swap(_str, s._str);
    254. std::swap(_size, s._size);
    255. std::swap(_capacity, s._capacity);
    256. }
    257. //find 函数实现
    258. //默认从0开始找
    259. size_t find(char ch, size_t pos = 0)
    260. {
    261. assert(pos < _size);
    262. for (size_t i = pos; i < _size; i++)
    263. {
    264. if (_str[i] == ch)
    265. {
    266. return i;
    267. }
    268. }
    269. return npos;
    270. }
    271. //函数重载找子串
    272. size_t find(const char* str, size_t pos = 0)
    273. {
    274. assert(_size > pos);
    275. //复用strstr
    276. char* p = strstr(_str + pos, str);
    277. if (p == nullptr)
    278. {
    279. return npos;
    280. }
    281. else
    282. {
    283. return p - _str;//指针减去指针为两个指针间的距离,也就是下标
    284. }
    285. }
    286. void clear()
    287. {
    288. _str[0] = '\0';
    289. _size = 0;
    290. }
    291. private:
    292. char* _str;
    293. size_t _size;
    294. size_t _capacity;
    295. static const size_t npos;
    296. //static const size_t nops=-1;
    297. //static const double dpos = 1.1; //不可以
    298. };
    299. const size_t string::npos = -1; //size_t为无符号整型,这里等于-1相当于等于最大整数
    300. //流提取 <<
    301. std::ostream& operator<<(std::ostream& out, const string& s)
    302. {
    303. for (auto ch : s)
    304. {
    305. out << ch;
    306. }
    307. return out;
    308. }
    309. //流插入 >>
    310. std::istream& operator>>(std::istream& in, string& s)
    311. {
    312. s.clear();
    313. char ch = in.get();
    314. char buff[128];
    315. size_t i = 0;
    316. while (ch != ' ' && ch != '\n')
    317. {
    318. buff[i++] = ch;
    319. if (i == 127)
    320. {
    321. buff[127] = '\0';
    322. s += buff;
    323. i = 0;
    324. }
    325. ch = in.get();
    326. }
    327. if (i != 0)
    328. {
    329. buff[i] = '\0';
    330. s += buff;
    331. }
    332. return in;
    333. }

    四、string相关OJ题

    415. 字符串相加 - 力扣(LeetCode)

    当我们学完string类时就可以使用库函数,这种题就相对

    1. class Solution {
    2. public:
    3. string addStrings(string num1, string num2)
    4. {
    5. int carry=0;//进位
    6. int end1=num1.size()-1;
    7. int end2=num2.size()-1;
    8. string s;
    9. while(end1>=0||end2>=0)
    10. {
    11. int val1=0;
    12. if(end1>=0)
    13. {
    14. val1=num1[end1]-'0';
    15. }
    16. int val2=0;
    17. if(end2>=0)
    18. {
    19. val2=num2[end2]-'0';
    20. }
    21. int sum=val1+val2+carry;
    22. if(sum>9)
    23. {
    24. sum-=10;
    25. carry=1;
    26. }
    27. else
    28. {
    29. carry=0;
    30. }
    31. s.insert(0,1,sum+'0');
    32. end1--;
    33. end2--;
    34. }
    35. if(carry==1)
    36. {
    37. s.insert(0,1,'1');
    38. }
    39. return s;
    40. }
    41. };
  • 相关阅读:
    SpringBoot项目如何实现热启动?
    hdfs常用命令行
    2022年戈登·贝尔奖授予等离子体加速器突破研究
    写出你所知道的测试工具,并写出他们的用途和优缺点
    计算机毕业设计Java网上课程资源管理系统(源码+系统+mysql数据库+Lw文档)
    BGP→→
    xxl-job2.3.1
    基于对数变换的图像美白增强,Matlab实现
    软件测试正在面试银行的可以看下这些面试题
    python基础
  • 原文地址:https://blog.csdn.net/m0_69323023/article/details/133972431