当前位置:   article > 正文

【C++】-- STL之String模拟实现_ostream& operator<<(ostream& out, const string& s)

ostream& operator<<(ostream& out, const string& s) { for (size_t i = 0; i <

目录

一、String类实现

1.string类的构造 

2.swap() 

3.拷贝构造

4.赋值运算符重载

5.析构

6.迭代器

7.operator[ ]

8.size()

9.c_str()

10.reserve() 

11.resize()

12.push_back()

13.append()

14.operator+=()

15.insert()

16.erase()

17.find()

18.operator>

19.operator==

20.operator>=

21.operator<

22.operator<=

23.operator!=

24.clear()

25.operator<<

26.operator>> 

 完整代码段

二、在线OJ题


 

一、String类实现

为了和库里面的string 区分开,使用命名空间delia将 string类和库里string隔离开

string类有3个成员变量:_str字符串内容、_size字符串大小、_capacity字符串容量

  1. namespace delia
  2. {
  3. class string
  4. {
  5. private:
  6. char* _str;
  7. size_t _size;
  8. size_t _capacity;
  9. }
  10. }

string的模拟实现包括:

1.string类的构造 

分配空间时,要多分配1个字节的空间,这1个字节是留给'\0'的,_size最大为申请字节数-1,_capacity最大也为申请字节数-1 

  1. //构造函数
  2. string(const char* str = "")
  3. {
  4. _str = new char[strlen(str) + 1];
  5. strcpy(_str, str);
  6. _size = strlen(str);
  7. _capacity = _size;
  8. }

 

2.swap() 

使用库里的swap函数交换*this和s的内容:包括_str字符串内容、_size字符串大小和_capacity字符串容量 

  1. //实现交换函数
  2. void swap(string& s)
  3. {
  4. //::指定调用全局的swap函数即库里的swap函数
  5. ::swap(_str, s._str);
  6. ::swap(_size, s._size);
  7. ::swap(_capacity, s._capacity);
  8. }

3.拷贝构造

(1)先使用s._str作为参数构造一个临时对象

(2)将临时对象tmp的内容和*this进行交换

注意:必须要在初始化列表进行初始化 ,否则交换完毕后tmp出了拷贝构造函数作用域会调用析构函数释放tmp在堆上申请的空间,因为如果_str没有被初始化为空指针,那么_str就是随机值,交换后,tmp对象的成员_str也是随机值,随机值的空间时不可以被释放的,会导致不可预知的错误;空指针时可以被释放的,因此_str必须被初始化为空指针。

  1. //现代拷贝构造
  2. string(const string& s)
  3. :_str(nullptr)
  4. , _size(0)
  5. , _capacity(0)
  6. {
  7. string tmp(s._str);
  8. swap(tmp);
  9. }

4.赋值运算符重载

使用swap()函数将*this的内容和s进行交换 

  1. //赋值运算符重载
  2. string& operator=(string s)
  3. {
  4. swap(s);
  5. return *this;
  6. }

 

5.析构

释放_str在对上申请的空间、将_size和_capacity置0 

  1. //析构函数
  2. ~string()
  3. {
  4. delete[] _str;
  5. _str = nullptr;
  6. _size = 0;
  7. _capacity = 0;
  8. }

 

6.迭代器

分两种:普通迭代器(可读可写)和const迭代器(只读) 

(1)普通迭代器

  1. //迭代器
  2. iterator begin()
  3. {
  4. return _str;
  5. }
  6. //迭代器
  7. iterator end()
  8. {
  9. return _str + _size;
  10. }

(2)const迭代器

  1. //const迭代器
  2. iterator begin() const
  3. {
  4. return _str;
  5. }
  6. //const迭代器
  7. iterator end() const
  8. {
  9. return _str + _size;
  10. }

 

7.operator[ ]

 也分为普通operator[ ](可读可写)和const operator[ ](只读)

char要加&,如果不加,那么return就是传值返回,返回的是_str[i]的拷贝,即临时对象,而临时对象具有常性,不能被修改,只能读;如果要对_str进行修改的话,char要加&,用传引用返回

  1. //const string对象遍历,只读
  2. char& operator[](size_t i) const
  3. {
  4. assert(i < _size);
  5. return _str[i];
  6. }
  7. //非const string对象遍历,可读可写
  8. char& operator[](size_t i)
  9. {
  10. assert(i < _size);
  11. return _str[i];
  12. }

 

8.size()

  1. //求string对象大小
  2. size_t size() const
  3. {
  4. return strlen(_str);
  5. }

 

9.c_str()

获取c形式字符串,将 const string* 类型 转化为 const char* 类型 

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

 

10.reserve() 

开空间,扩展_capacity,_size不变 

(1)申请新空间
(2)拷贝字符串
(3)释放旧空间
(4)指向新空间
(5)更新容量 

  1. void reserve(size_t n)
  2. {
  3. if (n > _capacity)
  4. {
  5. char* tmp = new char[n + 1];//1.申请新空间,多开的那一个空间,存放\0
  6. strncpy(tmp, _str, _size + 1);//2.将字符串包含\0在内都拷贝到新空间
  7. delete[] _str;//3.释放旧空间
  8. _str = tmp;//4.指向新空间
  9. _capacity = n;//5.更新容量
  10. }
  11. }

11.resize()

开空间+初始化,扩展_capacity,_size也要修改 

(1)当n<_size,无需增容 

(2)当n>_size,分两种情况
            ①_size < n <_capacity,无需增容,直接将_size到n位置置为val
            ②n >_capacity,需增容,并将_size到n位置置为val
          n>_size的这两种情况只有是否增容的区别,其他没有区别,可以合二为一

  1. void resize(size_t n, char val = '\0')//如果没有显式给出val,val为\0
  2. {
  3. //1.当n<_size,无需增容
  4. if (n < _size)
  5. {
  6. _size = n;//直接更新_size
  7. _str[_size] = '\0';//将_size位置置为\0
  8. }
  9. //2.当n>_size,分两种情况
  10. //1)_size < n <_capacity,无需增容,直接将_size到n位置置为val
  11. //2)n >_capacity,需增容,并将_size到n位置置为val
  12. //这两种情况只有是否增容的区别,其他没有区别
  13. else
  14. {
  15. if (n > _capacity)
  16. {
  17. reserve(n);
  18. }
  19. for (size_t i = _size; i < n; i++)
  20. {
  21. _str[i] = val;
  22. }
  23. _str[n] = '\0';//将n的位置置\0
  24. _size = n;//更新_size
  25. }
  26. }

 

12.push_back()

要考虑是否需要开空间

  1. //尾插一个字符
  2. void push_back(char ch)
  3. {
  4. //字符个数已经达到容量时,重新开空间
  5. if (_size == _capacity)
  6. {
  7. reserve(_capacity == 0 ? 4 : _capacity * 2);//如果是第一次开空间,就开4个字节,如果不是第一次开空间,就开成原来的2倍容量
  8. }
  9. _str[_size] = ch;//将字符ch缀到字符串末尾
  10. _str[_size + 1] = '\0';//字符ch后面加\0,表明字符串结束
  11. _size++;//字符串大小+1
  12. }

13.append()

将str内容copy至this._str+_size(*this._str的末尾)位置 

 

 

  1. //追加字符串
  2. void append(const char* str)
  3. {
  4. size_t len = _size + strlen(str);//函数执行完毕后字符串的大小
  5. if (len > _capacity)
  6. {
  7. reserve(len);//空间不够,增容
  8. }
  9. strcpy(_str + _size, str);//将str内容拷贝至_str末尾
  10. _size = len;//更新_size
  11. }

 

14.operator+=()

分为两种情况:

(1)+= 1个字符 ,使用push_back插入

(2)+= 字符串,使用append追加到字符串末尾

  1. //+= 1个字符
  2. string& operator+= (char c)
  3. {
  4. push_back(c);//尾插字符
  5. return *this;
  6. }
  7. //+= 字符串
  8. string& operator+= (const char* str)
  9. {
  10. append(str);//拼接字符串
  11. return *this;
  12. }

 

15.insert()

在指定位置插入字符:

(1)判断是否需要增容

(2)将pos位至字符串末尾的字符都向后挪一个位置

(3)将要插入的字符插入到pos位

(4)更新_size

 

  1. //insert插入一个字符
  2. string& insert(size_t pos, const char ch)
  3. {
  4. assert(pos <= _size);//pos必须小于等于字符串长度
  5. if (_size == _capacity)
  6. {
  7. reserve(2 * _capacity);//如果满了就增容
  8. }
  9. size_t end = _size + 1;
  10. while (end > pos)//将pos至_size之间的字符依次向后挪动一个位置,来腾出pos位置
  11. {
  12. _str[end] = _str[end - 1];
  13. end--;//end0时,因此end类型应为int,那么end--就为-1,pos为无符号数,不满足循环条件,退出循环
  14. //但如果end类型为size_t,那么end0时,end--就为-1,在内存中存储为无符号数(-1补码全1),满足循环条件,永远无法退出循环
  15. }
  16. _str[pos] = ch;//pos位置插入ch
  17. _size++;//更新_size
  18. return *this;
  19. }

16.erase()

删除字符,len为要删除的字符个数,分两种情况:

(1)从pos到字符串末尾的字符个数<要删除的字符个数,说明this._str长度不够删,那pos之后全都被删完了,直接将pos位置'\0',_size更新为pos即可。

 

(2)从pos到字符串末尾的字符个数≥要删除的字符个数,说明this._str长度够删,但是剩余的字符需要向前挪动len位

 

  1. //erase 删除字符
  2. string& erase(size_t pos, size_t len = npos)
  3. {
  4. assert(pos < _size);
  5. size_t leftLen = _size - pos;//从pos位置到字符串结束的字符长度
  6. if (leftLen < len)//1.pos之后的字符全部删掉
  7. {
  8. _str[pos] = '\0';
  9. _size = pos;
  10. }
  11. else//2.pos之后的字符删掉一部分,没删完的部分要挪到pos位置
  12. {
  13. strcpy(_str + pos, _str + pos + len);
  14. _size -= len;
  15. }
  16. return *this;
  17. }

 

17.find()

分为查找字符和查找字符串

  1. //查找字符
  2. size_t find(char ch, size_t pos = 0)
  3. {
  4. assert(pos < _size);
  5. for (size_t i = 0; i < _size; i++)
  6. {
  7. if (_str[i] == ch)
  8. {
  9. return i;//找到就返回字符所在位置
  10. }
  11. }
  12. return npos;//没找到就返回-1
  13. }
  1. //查找字符串(子串)
  2. size_t find(const char* str, size_t pos = 0)
  3. {
  4. assert(pos < _size);
  5. const char* ret = strstr(_str + pos, str);
  6. if (ret)
  7. {
  8. return ret - _str;//计算str与_str的偏移量,即str在_str中的下标
  9. }
  10. else
  11. {
  12. return npos;//没找到就返回-1
  13. }
  14. }

 

18.operator>

字符串比较,只需要实现>和==,剩余的可以用这两个实现重载 

  1. bool operator>(const string& s)
  2. {
  3. return strcmp(_str, s._str) < 0;
  4. }

 

19.operator==

  1. bool operator==(const string& s)
  2. {
  3. return strcmp(_str, s._str) == 0;
  4. }

 

20.operator>=

  1. bool operator>=(const string& s)
  2. {
  3. return (*this > s) || (*this == s);
  4. }

 

21.operator<

  1. bool operator<(const string& s)
  2. {
  3. return !(*this >= s);
  4. }

 

22.operator<=

  1. bool operator<=(const string& s)
  2. {
  3. return !(*this > s);
  4. }

 

23.operator!=

  1. bool operator!=(const string& s)
  2. {
  3. return !(*this == s);
  4. }

 

24.clear()

将字符串清空 

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

 

25.operator<<

输出重载<<让string直接输出打印,像内置类型一样,用范围for就可以实现

  1. ostream& operator<<(ostream& out, const string& s)
  2. {
  3. for (auto ch: s)
  4. {
  5. out << s;
  6. }
  7. return out;
  8. }

 

26.operator>> 

输入重载>>让string直接输入,像内置类型一样;从标准输入流读取字符,遇到' '或'\0'就停止 

  1. istream& operator>>(istream& in, string& s)
  2. {
  3. s.clear();
  4. char ch;
  5. ch = in.get();
  6. while (ch != ' ' && ch != '\0')
  7. {
  8. s += ch;
  9. ch = in.get();
  10. }
  11. return in;
  12. }

 完整代码段

  1. #pragma once
  2. #define _CRT_SECURE_NO_WARNINGS
  3. #include<iostream>
  4. #include<assert.h>
  5. #include<stdlib.h>
  6. using namespace std;
  7. //定义一个新的命名空间,和全局命名空间隔离开
  8. namespace delia
  9. {
  10. class string
  11. {
  12. public:
  13. typedef char* iterator;
  14. //迭代器
  15. iterator begin()
  16. {
  17. return _str;
  18. }
  19. //迭代器
  20. iterator end()
  21. {
  22. return _str + _size;
  23. }
  24. //const迭代器
  25. iterator begin() const
  26. {
  27. return _str;
  28. }
  29. //const迭代器
  30. iterator end() const
  31. {
  32. return _str + _size;
  33. }
  34. //构造函数
  35. string(const char* str = "")
  36. {
  37. _str = new char[strlen(str) + 1];//1是留给'/0'的,_size最大为申请字节数-1,_capacity也为申请字节数-1
  38. strcpy(_str, str);
  39. _size = strlen(str);
  40. _capacity = _size;
  41. }
  42. //现代拷贝构造
  43. string(const string& s)
  44. :_str(nullptr)
  45. , _size(0)
  46. , _capacity(0)
  47. {
  48. string tmp(s._str);
  49. swap(tmp);
  50. }
  51. //赋值运算符重载
  52. string& operator=(string s)
  53. {
  54. swap(s);
  55. return *this;
  56. }
  57. //析构函数
  58. ~string()
  59. {
  60. delete[] _str;
  61. _str = nullptr;
  62. _size = 0;
  63. _capacity = 0;
  64. }
  65. //实现交换函数
  66. void swap(string& s)
  67. {
  68. ::swap(_str, s._str);//::指定调用全局的swap函数即库里的swap函数
  69. ::swap(_size, s._size);
  70. ::swap(_capacity, s._capacity);
  71. }
  72. //const string对象遍历,只读
  73. char& operator[](size_t i) const//char要加&,如果不加,那么return就是传值返回,返回的是_str[i]的拷贝,临时对象,而临时对象具有常性,不能被修改,只能读
  74. //如果要对_str进行修改的话,char要加&,用传引用返回
  75. {
  76. assert(i < _size);
  77. return _str[i];
  78. }
  79. //非const string对象遍历,可读可写
  80. char& operator[](size_t i)
  81. {
  82. assert(i < _size);
  83. return _str[i];
  84. }
  85. //string对象大小
  86. size_t size() const
  87. {
  88. return strlen(_str);
  89. }
  90. //获取c形式字符串,将 const string* 类型 转化为 const char* 类型
  91. const char* c_str()
  92. {
  93. return _str;
  94. }
  95. //开空间,扩展_capacity,_size不变
  96. void reserve(size_t n)
  97. {
  98. //1.申请新空间
  99. //2.拷贝字符串
  100. //3.释放旧空间
  101. //4.指向新空间
  102. //5.更新容量
  103. if (n > _capacity)
  104. {
  105. char* tmp = new char[n + 1];//1.申请新空间,多开的那一个空间,存放\0
  106. strncpy(tmp, _str, _size + 1);//2.将字符串包含\0在内都拷贝到新空间
  107. delete[] _str;//3.释放旧空间
  108. _str = tmp;//4.指向新空间
  109. _capacity = n;//5.更新容量
  110. }
  111. }
  112. //开空间+初始化,扩展_capacity,_size也要修改
  113. void resize(size_t n, char val = '\0')//如果没有显式给出val,val为\0
  114. {
  115. //1.当n<_size,无需增容
  116. if (n < _size)
  117. {
  118. _size = n;//直接更新_size
  119. _str[_size] = '\0';//将_size位置置为\0
  120. }
  121. //2.当n>_size,分两种情况
  122. //1)_size < n <_capacity,无需增容,直接将_size到n位置置为val
  123. //2)n >_capacity,需增容,并将_size到n位置置为val
  124. //这两种情况只有是否增容的区别,其他没有区别
  125. else
  126. {
  127. if (n > _capacity)
  128. {
  129. reserve(n);
  130. }
  131. for (size_t i = _size; i < n; i++)
  132. {
  133. _str[i] = val;
  134. }
  135. _str[n] = '\0';//将n的位置置\0
  136. _size = n;//更新_size
  137. }
  138. }
  139. //尾插一个字符
  140. void push_back(char ch)
  141. {
  142. //字符个数已经达到容量时,重新开空间
  143. if (_size == _capacity)
  144. {
  145. reserve(_capacity == 0 ? 4 : _capacity * 2);//如果是第一次开空间,就开4个字节,如果不是第一次开空间,就开成原来的2倍容量
  146. }
  147. _str[_size] = ch;//将字符ch缀到字符串末尾
  148. _str[_size + 1] = '\0';//字符ch后面加\0,表明字符串结束
  149. _size++;//字符串大小+1
  150. }
  151. //追加字符串
  152. void append(const char* str)
  153. {
  154. size_t len = _size + strlen(str);//函数执行完毕后字符串的大小
  155. if (len > _capacity)
  156. {
  157. reserve(len);//空间不够,增容
  158. }
  159. strcpy(_str + _size, str);//将str内容拷贝至_str末尾
  160. _size = len;//更新_size
  161. }
  162. //+= 1个字符
  163. string& operator+= (char c)
  164. {
  165. push_back(c);//尾插字符
  166. return *this;
  167. }
  168. //+= 字符串
  169. string& operator+= (const char* str)
  170. {
  171. append(str);//拼接字符串
  172. return *this;
  173. }
  174. //insert插入一个字符
  175. string& insert(size_t pos, const char ch)
  176. {
  177. assert(pos <= _size);//pos必须小于等于字符串长度
  178. if (_size == _capacity)
  179. {
  180. reserve(2 * _capacity);//如果满了就增容
  181. }
  182. size_t end = _size + 1;
  183. while (end > pos)//将pos至_size之间的字符依次向后挪动一个位置,来腾出pos位置
  184. {
  185. _str[end] = _str[end - 1];
  186. end--;//end0时,因此end类型应为int,那么end--就为-1,pos为无符号数,不满足循环条件,退出循环
  187. //但如果end类型为size_t,那么end0时,end--就为-1,在内存中存储为无符号数(-1补码全1),满足循环条件,永远无法退出循环
  188. }
  189. _str[pos] = ch;//pos位置插入ch
  190. _size++;//更新_size
  191. return *this;
  192. }
  193. //erase 删除字符
  194. string& erase(size_t pos, size_t len = npos)
  195. {
  196. assert(pos < _size);
  197. size_t leftLen = _size - pos;//从pos位置到字符串结束的字符长度
  198. if (leftLen < len)//1.pos之后的字符全部删掉
  199. {
  200. _str[pos] = '\0';
  201. _size = pos;
  202. }
  203. else//2.pos之后的字符删掉一部分,没删完的部分要挪到pos位置
  204. {
  205. strcpy(_str + pos, _str + pos + len);
  206. _size -= len;
  207. }
  208. return *this;
  209. }
  210. //查找字符
  211. size_t find(char ch, size_t pos = 0)
  212. {
  213. assert(pos < _size);
  214. for (size_t i = 0; i < _size; i++)
  215. {
  216. if (_str[i] == ch)
  217. {
  218. return i;//找到就返回字符所在位置
  219. }
  220. }
  221. return npos;//没找到就返回-1
  222. }
  223. //查找字符串(子串)
  224. size_t find(const char* str, size_t pos = 0)
  225. {
  226. assert(pos < _size);
  227. const char* ret = strstr(_str + pos, str);
  228. if (ret)
  229. {
  230. return ret - _str;//计算str与_str的偏移量,即str在_str中的下标
  231. }
  232. else
  233. {
  234. return npos;//没找到就返回-1
  235. }
  236. }
  237. //字符串比较,只需要实现>==
  238. bool operator>(const string& s)
  239. {
  240. return strcmp(_str, s._str) < 0;
  241. }
  242. bool operator==(const string& s)
  243. {
  244. return strcmp(_str, s._str) == 0;
  245. }
  246. // 其它4个运算符都可以对>==这两个运算符进行重载
  247. bool operator>=(const string& s)
  248. {
  249. return (*this > s) || (*this == s);
  250. }
  251. bool operator<(const string& s)
  252. {
  253. return !(*this >= s);
  254. }
  255. bool operator<=(const string& s)
  256. {
  257. return !(*this > s);
  258. }
  259. bool operator!=(const string& s)
  260. {
  261. return !(*this == s);
  262. }
  263. void clear()
  264. {
  265. _size = 0;
  266. _str[0] = '\0';
  267. }
  268. private:
  269. char* _str;
  270. size_t _size;
  271. size_t _capacity;
  272. static const size_t npos;
  273. };
  274. const size_t string::npos = -1;//npos初始化
  275. //输出重载<<string直接输出打印,像内置类型一样,用范围for就可以实现
  276. ostream& operator<<(ostream& out, const string& s)
  277. {
  278. for (auto ch: s)
  279. {
  280. out << s;
  281. }
  282. return out;
  283. }
  284. //输入重载>>让string直接输入,像内置类型一样;从标准输入流读取字符,遇到' '或'\0'就停止
  285. istream& operator>>(istream& in, string& s)
  286. {
  287. s.clear();
  288. char ch;
  289. ch = in.get();
  290. while (ch != ' ' && ch != '\0')
  291. {
  292. s += ch;
  293. ch = in.get();
  294. }
  295. return in;
  296. }
  297. void f(const string& s)
  298. {
  299. for (size_t i = 0; i < s.size(); i++)
  300. {
  301. cout << s[i] << " ";
  302. }
  303. cout << endl;
  304. }
  305. void test_string1()
  306. {
  307. string s1("hello world");
  308. string s2(s1);
  309. string s3("cplusplus.com");
  310. std::swap(s1, s3);//调用库里的swap函数,3次深拷贝,再把原来的空间释放掉,再开一样大的空间,代价大
  311. s1.swap(s3);//调用delia::string类里面的成员函数swap,仅仅只是成员变量的交换,s3指向了s1的空间,s1指向了s3的空间
  312. string s4 = s1.c_str();
  313. s1[2] = 'w';
  314. f(s1);//h e w l o w o r l d
  315. for (size_t i = 0; i < s1.size(); i++)
  316. {
  317. cout << s1[i] << " ";
  318. }
  319. cout << endl;//h e w l o w o r l d
  320. }
  321. void test_string2()
  322. {
  323. string s1("hello world");
  324. //使用迭代器遍历
  325. string::iterator it = s1.begin();
  326. while (it != s1.end())
  327. {
  328. cout << *it << " ";
  329. it++;
  330. }
  331. cout << endl;//h e l l o w o r l d
  332. //使用范围for遍历,范围for会被编译器替换成迭代器形式,如果把17-26行屏蔽,会发现编译不过
  333. for (auto ch : s1)
  334. {
  335. cout << *it << " ";
  336. }
  337. cout << endl;//h e l l o w o r l d
  338. }
  339. void test_string3()
  340. {
  341. string s1("hello world");
  342. s1 += "abc";
  343. for (auto& ch : s1)
  344. {
  345. cout << ch << " ";
  346. }
  347. cout << endl;//h e l l o w o r l d a b c
  348. s1 += "xyz";
  349. for (auto& ch : s1)
  350. {
  351. cout << ch << " ";
  352. }
  353. cout << endl;//h e l l o w o r l d a b c x y z
  354. }
  355. void test_string4()
  356. {
  357. string s1("hello world");
  358. s1 += '#';
  359. for (auto ch : s1)
  360. {
  361. cout << ch << " ";
  362. }
  363. cout << endl;//hello world#
  364. s1 += "xyz";
  365. for (auto ch : s1)
  366. {
  367. cout << ch << " ";
  368. }
  369. cout << endl;//hello world#xyz
  370. s1 += "!!!!!!!!!!!!!!!!!!!!";
  371. for (auto ch : s1)
  372. {
  373. cout << ch << " ";
  374. }
  375. cout << endl;//hello world#xyz!!!!!!!!!!!!!!!!!!!!
  376. }
  377. void test_string5()
  378. {
  379. string s1("hello world");
  380. s1.resize(3);
  381. cout << s1.c_str() << endl;//hel
  382. }
  383. void test_string6()
  384. {
  385. string s1("hello");
  386. s1.resize(6, 'a');
  387. cout << s1.c_str() << endl;//helloa
  388. }
  389. void test_string7()
  390. {
  391. string s1("hello");
  392. s1.resize(9, 'o');
  393. cout << s1.c_str() << endl;//helloooo
  394. }
  395. void test_string8()
  396. {
  397. string s1("hello");
  398. s1.insert(0, 'u');
  399. cout << s1.c_str() << endl;//uhello
  400. }
  401. void test_string9()
  402. {
  403. string s1("hello");
  404. s1.erase(0, 2);
  405. cout << s1.c_str() << endl;//llo
  406. string s2("world");
  407. s2.erase(1);//如果不给len,那么npos=-1,无符号数为4294967295,删除从位置为1-4294967295的字符,把后面的字符全部删除了
  408. cout << s2.c_str() << endl;//w
  409. }
  410. void test_string10()
  411. {
  412. string s1("hello world");
  413. cout << s1.find("rl",6) << endl;//8,从s1中的第6个位置开始查找"rl"字符串
  414. }
  415. void test_string11()
  416. {
  417. std::string s("hello");
  418. cin >> s;
  419. cout << s << endl;
  420. }
  421. }
  422. int main()
  423. {
  424. //delia::test_string1();
  425. //delia::test_string2();
  426. //delia::test_string3();
  427. //delia::test_string4();
  428. //delia::test_string5();
  429. //delia::test_string6();
  430. //delia::test_string7();
  431. //delia::test_string8();
  432. //delia::test_string9();
  433. //delia::test_string10();
  434. delia::test_string11();
  435. return 0;
  436. }

二、在线OJ题

替换空格 OJ链接

分析:(1)如果使用string的replace或erase+insert都要挪动数据,效率低
           (2)考虑直接用新串,用新串需要分配多大空间?一个空格占1个字节,‘%20’占3个字节,替换后,每个空格都比原来多两个字节,新串空间应为:原串长度+2*空格数

  1. class Solution {
  2. public:
  3. string replaceSpace(string s) {
  4. //1.计算空格数
  5. size_t spaceCount = 0;
  6. for(auto ch:s)
  7. {
  8. if(ch == ' ')
  9. {
  10. spaceCount++;
  11. }
  12. }
  13. //2.声明新串
  14. string ret;
  15. //3.为新串分配空间:从空格变为%20,长度增加2
  16. ret.reserve(s.size()+2*spaceCount);
  17. //4.将空格替换为%20
  18. for(auto ch:s)
  19. {
  20. if(ch != ' ')
  21. {
  22. ret += ch;
  23. }
  24. else
  25. {
  26. ret += "%20";
  27. }
  28. }
  29. return ret;
  30. }
  31. };

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/490407
推荐阅读
相关标签
  

闽ICP备14008679号