一、标准库中的string类
1.string类文档介绍
(1)字符串是表示字符序列的类。
(2)标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性。
(3)string类是使用char(即作为他的字符类型,使用它的默认char_traits和分配器类型)。
(4)string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并使用char_traits和allocator作为basic_string的默认参数。
(5)这个类独立于所使用的编码来处理字节,如果用来处理多字节或变长字符(如utf-8)的序列,这个类的所有成员(如长度、大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作。
2.string类常用接口介绍
2.1string类对象的常见构造
2.2string类对象的容量操作
注意:
(1)size和length方法的底层实现原理完全相同,引入size的原因是为了与其他容器的接口保持一致,一般情况下基本都是使用size。
(2)clear只是将string中有效字符清空,不改变底层空间大小。
(3)resize(size_t n)与resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时,resize(size_t n)用0来填充多出的元素空间,而resize(size_t n, char c)是用字符c来填充多出的元素空间。
注意:resize在改变元素个数时,若是将元素个数增多,可能会改变底层容量的大小,若是将元素个数减少,底层空间总大小不变。
(4)reserve(size_t res_arg=0):为string预留空间,不改变有效元素的个数,当reserve的参数小于string的底层空间总大小时,reserve不会改变容量大小。
2.3string类对象的访问及遍历操作
2.4string类对象的修改操作
二、模拟实现string类
1.实现的接口
1.1类默认的成员函数
构造函数
拷贝构造函数
赋值运算符重载
析构函数
1.2迭代器相关
迭代器通过指针模拟实现。
1.3容量相关
1.4元素访问
1.5元素修改相关
字符/字符串追加
1.6字符串操作相关
获取C语言格式字符串
查找字符
获取子串
字符串交换
1.7IO操作相关
输入输出
2.代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <assert.h>
using namespace std;
namespace MyString {
class string {
public:
//用指针模拟实现迭代器
typedef char* iterator;
typedef char* reverse_iterator;
/*--------------默认成员函数--------------*/
//默认构造
string(const char* str = "") {
if (str == nullptr) str = "";
_size = strlen(str);
_capacity = _size;
_str = new char[_size + 1];//需要加上\0所占的空间
strcpy(_str, str);
}
//拷贝构造
string(const string& s)
: _str(nullptr)
, _size(0)
,_capacity(0)
{
//传统写法
//_str = new char[strlen(s._str) + 1];
//strcpy(_str, s._str);
string str_temp(s._str);
this -> swap(str_temp);
}
//n_char构造
string(size_t n, char ch) {
_size = n;
_capacity = n;
_str = new char[n + 1];
memset(_str, ch, n);
_str[n] = '\0';
}
//赋值运算符重载
string& operator=(string s) {
if (this != &s) {//防止自己给自己赋值
//传统写法
//char* temp = new char[strlen(s._str) + 1];
//strcpy(temp, s._str);
//delete[] _str;
//_str = temp;
this -> swap(s);
}
return *this;
}
//析构
~string() {
if (_str) {
delete[] _str;
_str = nullptr;
}
}
/*--------------迭代器--------------*/
/*使用指针模拟实现*/
iterator begin() {
return _str;
}
iterator end() {
return _str + _size;
}
reverse_iterator rbegin() {
return end();
}
reverse_iterator rend() {
return begin();
}
/*--------------容量--------------*/
size_t size() const {
return _size;
}
size_t capacity() const {
return _capacity;
}
bool empty() const {
return 0 == _size;
}
void clear() {
_size = 0;
}
void resize(size_t new_size, char ch) {
if (new_size > _size) {
size_t old_size = _size;
if (new_size > _capacity) {//需要扩容
reserve(new_size);
}
memset(_str + _size, ch, new_size - old_size);
}
_size = new_size;
_str[_size] = '\0';
}
void resize(size_t n) {
resize(n, 0);
}
void reserve(size_t new_capacity) {//扩容
size_t old_capacity = _capacity;
if (new_capacity > old_capacity) {
char* temp = new char[new_capacity + 1];
strcpy(temp, _str);
delete[] _str;
_str = temp;
_capacity = new_capacity;
}
}
/*--------------元素访问--------------*/
char& operator[](size_t index) {
assert(index < _size);
return _str[index];
}
const char& operator[](size_t index) const {
assert(index < _size);
return _str[index];
}
/*--------------元素修改--------------*/
void push_back(char ch) {
if (_size == _capacity) {//需要扩容
if (_capacity == 0) _capacity = 1;//若初始为0,按2倍扩容方式则无法扩容
reserve(_capacity * 2);
}
_str[_size] = ch;
_size++;
_str[_size] = '\0';
}
string& operator+=(char ch) {
push_back(ch);
return *this;
}
string& operator+=(const string& s) {
*this += s._str;
return *this;
}
string& operator+=(const char* s) {
size_t len = strlen(s);
char* temp = new char[_size + len + 1];
strcpy(temp, _str);
strcat(temp, s);
delete[] _str;
_str = temp;
_size += len;
_capacity = _size;
return *this;
}
/*--------------字符串操作--------------*/
const char* c_str() const {
return _str;
}
size_t find(char ch, size_t pos = 0) {
for (size_t i = pos; i < _size; ++i) {
if (_str[i] == ch) return i;
}
return npos;
}
size_t rfind(char ch, size_t pos = npos) {
//注意无符号-1是一个非常大的数字
pos = pos < _size ? pos : _size - 1;
for (int i = pos; i >= 0; --i) {
if (_str[i] == ch) return i;
}
return npos;
}
string substr(size_t pos, size_t n = npos) {
if (n == npos) n = _size;// 没有传入n时,最多截取_size长度
if (pos + n >= _size) {
n = _size - pos;
}
char* temp = new char[n + 1];
strncpy(temp, _str + pos, n);
temp[n] = '\0';
string sub(temp);
delete[] temp;
return sub;
}
//交换函数
void swap(string& s) {
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
/*--------------IO操作--------------*/
friend ostream& operator<<(ostream& _cout, const string& s) {
_cout << s._str;
return _cout;
}
friend istream& operator>>(istream& _cin, string& s) {
//直接输入无法扩容
while (1) {
char ch = _cin.get();
if (ch == '\n' || ch == ' ') break;
s.push_back(ch);
}
return _cin;
}
private:
char* _str;
size_t _size;
size_t _capacity;
public:
static size_t npos;
};
size_t string::npos = -1;
}