string 类中常见操作及其模拟实现

x33g5p2x  于2021-11-22 转载在 其他  
字(11.8k)|赞(0)|评价(0)|浏览(426)

1.string容器的基本概念

本质:string是c++类型的字符串,其本质是一个封装好的类
string和char的区别:
1.char
是一个指针
2.string是一个内部封装了char* 的类,管理这个字符串,是一个char型容器
特点:
string类内部封装了很多成员函数
例如:查找find,拷贝copy,删除delete,替换replace,插入insert
string管理char
所分配的内存,不用担心赋值越界和取值越界等问题,由类内部负责

2.string容器的常用操作string 的构造函数

  1. string();//创建一个空的字符串例如:string str;
  2. string(const string &str)//使用一个string 对象去初始化另外一个string 对象
  3. string(const char*str)//使用字符串s初始化
  4. string (int n,char c)//使用n个字符串c初始化

下面我们来实验

1.string ()

  1. #include<iostream>
  2. using namespace std;
  3. #include<string>
  4. int main()
  5. {
  6. string s;
  7. cout << s;
  8. }

运行结果:

我们可以发现字符串是空的

2.string (const string&str);

  1. #include<iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. string s = "abvede";
  6. string s1(s);
  7. cout << s1;
  8. }

运行结果:

3.string (const char*str);

  1. #include<iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. string s1("abdedf");
  6. cout << s1;
  7. }

运行结果:

4.string (int n,char c)

  1. #include<iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. string s1(3, 'a');
  6. cout << s1;
  7. }

 3.string 类的基本赋值操作

  1. string &operator=(const char*s)//将char*类型字符串赋值给当前字符串
  2. string &operator=(const string &s)把字符串s赋值给当前字符串
  3. string& operator=(char c)把字符赋值给当前字符串
  4. string &assign (const char*s)把字符串s赋给当前字符串
  5. string &assign(const char*s,int n)把字符串s的前n个字符赋给当前字符串
  6. string &assign(const string&s)把字符串s赋给当前字符串
  7. string &assign(int n,char c)用n个字符赋给当前字符串
  8. string &assign(const string &s,int start,int n)将sstart开始n个字符赋值给字符串

例:string &operator=(const char*s)

  1. #include<iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. string s = "aveddfhf";
  6. cout << s << endl;
  7. return 0;
  8. }

运行结果:

2.string &operator=(const string&s)

  1. #include<iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. string s = "aveddfhf";
  6. string s1;
  7. s1 = s;
  8. cout << s1<< endl;
  9. return 0;
  10. }

运行结果:

3.string&operator=(char c);

  1. #include<iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. string s1;
  6. s1 = 'a';
  7. cout << s1 << endl;
  8. return 0;
  9. }

4.string  &assign(const char*s)

  1. #include<iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. string s1;
  6. s1.assign("djfgfjdfgh");
  7. cout << s1 << endl;
  8. }

运行结果:

string 存取字符字符操作及遍历方法

  1. //string存取字符操作
  2. //char&operator[](int n);通过[]的方式取字符
  3. //char&at(int n);通过at的方式获取字符

例:

  1. #include<iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. string str = "hello world";
  6. for (int i = 0; i < str.size(); i++) {
  7. cout << str[i] << endl;
  8. }
  9. }

运行结果:

通过at 的方式来获取:

  1. #include<iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. string str = "hello world";
  6. for (int i = 0; i < str.size(); i++) {
  7. cout << str.at(i) << endl;
  8. }
  9. }

运行结果:

我们可以发现两者的运行结果没有取别,拿这两种方式有什么区别吗?

[]和at的区别:

[]访问越界程序会直接挂掉,而at访问越界会抛出异常out_of_range

  1. #include<iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. string str = "hello world";
  6. cout << str[100] << endl;
  7. }

运行结果:


  

我们可以看到此时程序直接崩溃了

通过at的方式来获取:

  1. #include<iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. string str = "hello world";
  6. try {
  7. cout << str.at(100) << endl;
  8. }
  9. catch (out_of_range& e) {
  10. cout << e.what() << endl;
  11. }
  12. }

运行结果:

string 中如何访问最后一个元素或者第一个元素

访问第一个元素:

1.通过[]

2.通过at

3.通过成员函数的方法 对象.front();

4.通过迭代器

访问最后一个元素与访问第一个元素类似

1.通过[]

2.通过at

3.通过成员函数的方法

4.通过迭代器

例:

  1. #include<iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. string str = "hello world";
  6. cout << str[0] << endl;//通过[]
  7. cout << str.at(0) << endl;//通过at
  8. cout << str.front() << endl;//通过成员函数
  9. cout << *str.begin() << endl;//通过迭代器
  10. return 0;
  11. }

运行结果:

访问最后一个元素:

  1. #include<iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. string str = "hello world";
  6. cout << str[str.size() - 1] << endl;
  7. cout << str.at(str.size() - 1) << endl;
  8. cout << str.back() << endl;
  9. cout << *(str.end() - 1) << endl;//注意str.end()返回的是最后一个元素的下一个位置
  10. return 0;
  11. }

运行结果:

2.string对象的几种遍历方式

1.通过[]或者at加for或者while循环遍历

  1. #include<iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. string str = "hello world";
  6. for (int i = 0; i < str.size(); i++) {
  7. cout << str[i];
  8. }
  9. }

运行结果:

2.通过迭代器

  1. #include<iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. string str = "hello world";
  6. string::iterator it = str.begin();
  7. while (it != str.end()) {
  8. cout << *it;
  9. it++;
  10. }
  11. return 0;
  12. }

运行结果:

3.通过范围for来遍历

  1. #include<iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. string str = "hello world";
  6. for (auto& e : str) {
  7. cout << e;
  8. }
  9. }

运行结果:

4.通过algorithm里面的for_each来遍历

  1. #include<iostream>
  2. using namespace std;
  3. #include<algorithm>
  4. void myprint(char ch) {
  5. cout << ch;
  6. }
  7. int main()
  8. {
  9. string str = "hello world";
  10. for_each(str.begin(), str.end(), myprint);
  11. }

运行结果:

string 中的拼接操作

  1. /string 类中的拼接操作
  2. //string &operator+=(const char*str)重载+=
  3. //string &operator+=(const string&str)重载+=
  4. //string &operator+=(const char ch)重载+=
  5. //string &append (const char*str)把字符串str连接到当前字符串结尾
  6. //string &append(const char*str,int n)把字符串str前n个字符连接到当前字符串结尾
  7. //string &append(const string&s)和+=一样
  8. //string&append(const string&s int pos,int n)把字符串s中从pos位置开始的n个字符连接到当前字符串
  9. //string &append(int n,char c)在当前字符串结尾添加n个字符c

在这里就不一一测试

string&operator(const char ch)

  1. #include<iostream>
  2. using namespace std;
  3. #include<algorithm>
  4. int main()
  5. {
  6. string s = "ab";
  7. s += 'c';
  8. cout << s << endl;
  9. }

运行结果:

string&operator+=(const char*str)

  1. #include<iostream>
  2. using namespace std;
  3. #include<algorithm>
  4. int main()
  5. {
  6. string s = "ab";
  7. s += "abcdeff";
  8. cout<<s<<endl;
  9. }

运行结果:

string &append(const char*str,int n);

  1. #include<iostream>
  2. using namespace std;
  3. #include<algorithm>
  4. int main()
  5. {
  6. string s = "ab";
  7. s.append("abcdef", 3);
  8. cout << s << endl;
  9. }

运行结果:

string&append(int n,char ch);

  1. #include<iostream>
  2. using namespace std;
  3. #include<algorithm>
  4. int main()
  5. {
  6. string s = "ab";
  7. s.append(3, '0');
  8. cout << s << endl;
  9. }

运行结果:

string 中的查找和替换

  1. //int find(const string&str,int pos=0)const查找str第一次出现的位置,默认从0号位置开始找
  2. //int find(const char*s,int pos=0)查找s第一次出现的位置从pos位置开始找
  3. // int find(const char*s,int pos,int n)从pos位置查找s的前n个字符第一次出现的位置
  4. //int find(const char c,int pos=0)查找字符c第一次出现的位置
  5. //int rfind(const string&str,int pos=npos)const查找str最后一次出现的位置,从pos位置开始找
  6. //int rfind(const char*s,int pos=npos)const 查找s最后一次出现的位置,从pos位置开始找
  7. //int rfind(const char*s,int pos,int n)从pos位置开始查找s前n个字符第一次出现的位置
  8. //int rfind(const char ch,int pos=0)const 查找字符ch最后一次出现的位置
  9. //string &replace (int pos,int n,const string&str)替换从pos位置开始n个字符为字符串
  10. //string &replace (int pos,int n,const char*s)替换从pos开始的n个字符为字符串s
  1. #include<iostream>
  2. using namespace std;
  3. #include<algorithm>
  4. int main()
  5. {
  6. string s1="abcdef";
  7. string s2 = "abc";
  8. int ret = s1.find(s2);
  9. cout << ret;
  10. }

运行结果:

  1. #include<iostream>
  2. using namespace std;
  3. #include<algorithm>
  4. int main()
  5. {
  6. string s1="abcdef";
  7. string s2 = "abc";
  8. int ret = s1.find(s2);
  9. cout << ret;
  10. }

我们在s1中查找s2中从0号位置开始

运行结果:

int rfind(string&s,int pos=npos);

  1. #include<iostream>
  2. using namespace std;
  3. #include<algorithm>
  4. int main()
  5. {
  6. string s1="abcdefabc";
  7. string s2 = "abc";
  8. int ret = s1.rfind(s2);
  9. cout << ret;
  10. }

运行结果:

如果没有找到则会返回-1

find和rfind的区别:

find 是从从左往右找,而rfind是从右往左找

string 字串

  1. string substr(int pos=0,int n=npos)const 返回由pos开始的n个字符组成的字符串

  1. #include<iostream>
  2. using namespace std;
  3. #include<algorithm>
  4. int main()
  5. {
  6. string s1="abcdefabc";
  7. cout << s1.substr(0, 3);
  8. }

运行结果:

string插入和删除操作

  1. /string&insert(int pos,const char*s)插入字符串
  2. //string&insert(int pos,const string&s)插入字符串
  3. //string&insert(int pos,int n,char c)在指定位置插入n个字符c
  4. //string&erase(int pos,int n=npos)删除从pos开始的n个字符

在这里就不测试了可以自己下来测试一下

string 中的c_str(重点)

string.c_str是Borland封装的String类中的一个函数,它返回当前字符串的首字符地址。

c_str函数的返回值是const char的,不能直接赋值给char,所以就需要我们进行相应的操作转化。
 

  1. #include<iostream>
  2. using namespace std;
  3. #include<algorithm>
  4. int main()
  5. {
  6. string s = "Chelse";
  7. const char* str = s.c_str();
  8. cout << str << endl;
  9. s[1] = 'm';
  10. cout << str << endl;
  11. }

运行结果:

第一个输出 当然是 Chelse;
第二个输出呢: Chelse还是Cmelse呢?
答案是Cmelse。
const char的值应该是个常量啊,怎么还能改变值呢?
这就是很多人遇到的坑儿,也许面试的时候你会顺利的回答出来,但是在实际的工程中,往往掉进坑儿里,难以自拔。
const char
, char const*, char* const的区别是什么?老
const char与char const是等价的,指的是指向字符常量的指针,即指针可以改变指向但其指向的内容不可以改变。
而char* const相反,指的是常量指针,即指向不可以改变但指针指向的内容可以改变。因此这里的const char*指向的内容本类是不可以改变的。

那么这里为什么改变了呢?这跟str这个const char的生命周期及string类的实现有关,string的c_str()返回的指针是由string管理的,因此它的生命期是string对象的生命期,而string类的实现实际上封装着一个char的指针,而c_str()直接返回该指针的引用,因此string对象的改变会直接影响已经执行过的c_str()返回的指针引用。

string 模拟实现:

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

相关文章