本文主要介绍string类和该类常用的接口,并根据接口功能对其进行模拟实现。
目录
在使用string类时,必须包含#include
(下面我们只介绍最常用的接口)
(文档链接)
| 函数名称 | 功能说明 |
|---|---|
| string(); | 构造空的string类对象,即空字符串 |
| string (const string& str); | 用C-string来构造string类对象 |
| string (size_t n, char c); | string类对象中包含n个字符c |
| string (const string& str); | 拷贝构造函数 |
演示:
- string(); //构造空的string类对象,即空字符串
- string (const string& str);//用C-string来构造string类对象
- string (size_t n, char c);//string类对象中包含n个字符c
- string(const string&s) //拷贝构造函数
- void StringTest()
- {
- string s1; // 构造空的string类对象s1
- string s2("hello world"); // 用C格式字符串构造string类对象s2
- string s3(6,'x');//有6个'x'字符的字符串构造string类对象s3
- string s4(s2); // 拷贝构造s4
- }
| 函数名称 | 功能说明 |
|---|---|
| size | 返回字符串有效字符长度 |
| length | 返回字符串有效字符长度 |
| capacity | 返回空间总大小 |
| empty | 检测字符串释放为空串,是返回true,否则返回false |
| clear | 清空有效字符 |
| reserve | 为字符串预留空间 |
| resize | 将有效字符的个数该成n个,多出的空间用字符c填充 |
1.size 和 length:返回字符串有效字符长度
- size_t size() const;
- size_t length() const;
- int main()
- {
- string s1("hello world");
- cout << s1.size() << endl;//11
- cout << s1.length() << endl;//11
-
- return 0;
- }
size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一 致,一般情况下基本都是用size()。
2.capacity:返回空间总大小
size_t capacity() const;
- int main()
- {
- string s1("hello world");
- string s2("C++");
- cout << s1.capacity() << endl;//15
- cout << s2.capacity() << endl;//15
- return 0;
- }
返回当前对象中该字符串所分配的存储空间的大小。
3.empty:检测字符串释放为空串,是返回true,否则返回false
bool empty() const;
- int main()
- {
- string s1("hello world");
- string s2;
- if (s1.empty())
- cout << "s1 is empty" << endl;
- if (s2.empty())
- cout << "s2 is empty" << endl;
- return 0;
- }
输出:s2 is empty
4.clear:清空有效字符
void clear();
- int main()
- {
- string s("hello world");
- cout << s.size() << endl;// 11
- cout << s.length() << endl;// 11
- cout << s.capacity() << endl;// 15
- cout << s << endl;// hello world
-
- s.clear();
- cout << s.size() << endl;// 0
- cout << s.capacity() << endl;// 15
- return 0;
- }
该函数将s中的字符串清空,注意清空时只是将size清0,不改变底层空间的大小
5.reserve:为字符串预留空间
void reserve (size_type n = 0);
- int main()
- {
- string s("hello world");
- cout << s.size() << endl;// 11
- cout << s.capacity() << endl;// 15
-
- s.reserve(100);
- cout << s.size() << endl;// 11
- cout << s.capacity() << endl;// 111
-
- s.reserve(50);
- cout << s.size() << endl;// 11
- cout << s.capacity() << endl;// 111
- }
为string预留空间,不改变有效元素个数,当reserve的参数小于 string的底层空间总大小时,reserver不会改变容量大小。
如果提前已经知道string中大概要放多少个元素,可以提前将string中空间设置好,避免频繁扩容。
6.resize:将有效字符的个数该成n个,多出的空间用字符c填充
- void resize (size_t n);
- void resize (size_t n, char c);
- int main()
- {
- string s;//空字符串
-
- // 将s中有效字符个数增加到10个,多出位置用'a'进行填充
- s.resize(10, 'a');
- cout << s.size() << endl; // 10
- cout << s.capacity() << endl;// 15
- cout << s << endl; // “aaaaaaaaaa”
-
- // 将s中有效字符个数增加到15个,多出位置用缺省值'\0'进行填充
- // 注意此时s中有效字符个数已经增加到15个
- s.resize(15);
- cout << s.size() << endl;// 15
- cout << s.capacity() << endl;// 15
- cout << s << endl; // "aaaaaaaaaa\0\0\0\0\0"
-
- // 将s中有效字符个数缩小到5个
- s.resize(5);
- cout << s.size() << endl;// 5
- cout << s.capacity() << endl;// 15
- cout << s << endl; // "aaaaa"
- return 0;
- }
resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字 符个数增多时:resize(n)用 0 来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的 元素空间。
注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
| 函数名称 | 功能说明 |
|---|---|
| operator[] | 返回pos位置的字符,const string类对象调用 |
| begin+ end | begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器 |
| rbegin + rend | begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的逆向迭代器 |
| 范围for | C++11支持更简洁的范围for的新遍历方式 |
1.operator[]:返回pos位置的字符,const string类对象调用
- char& operator[] (size_t pos);
- const char& operator[] (size_t pos) const;
- int main()
- {
- string s1("hello world");
- const string s2("Hello world");
- cout << s1 << " " << s2 << endl;//hello world Hello world
- cout << s1[0] << " " << s2[0] << endl;//h H
-
- s1[0] = 'H';
- cout << s1 << endl;//Hello world
- // s2[0] = 'h'; 代码编译失败,因为const类型对象不能修改
- }
2.string类对象的遍历操作
3种遍历方式:①for+operator[] ②迭代器 ③范围for
- iterator begin();
- const_iterator begin() const;
-
- iterator end();
- const_iterator end() const;
-
- reverse_iterator rbegin();
- const_reverse_iterator rbegin() const;
-
- reverse_iterator rend();
- const_reverse_iterator rend() const;
- int main()
- {
- string s("hello world");
- // 3种遍历方式:
- // 需要注意的以下三种方式除了遍历string对象,还可以遍历是修改string中的字符,
- // 另外以下三种方式对于string而言,第一种使用最多
- // 1. for+operator[]
- for (size_t i = 0; i < s.size(); ++i)
- cout << s[i];
-
- //hello world
- cout << endl;
-
- // 2.迭代器
- string::iterator it = s.begin();
- while (it != s.end())
- {
- cout << *it;
- ++it;
- }
- //hello world
- cout << endl;
-
- // string::reverse_iterator rit = s.rbegin();
- // C++11之后,直接使用auto定义迭代器,让编译器推到迭代器的类型
- // 逆置打印
- auto rit = s.rbegin();
- while (rit != s.rend())
- {
- cout << *rit;
- ++rit;
- }
- //dlrow olleh
- cout << endl;
-
- // 3.范围for
- for (auto ch : s)
- cout << ch;
- //hello world
- return 0;
- }
| 函数名称 | 功能说明 |
|---|---|
| push_back | 在字符串后尾插字符c |
| append | 在字符串后追加一个字符串 |
| insert | 在字符串pos位置插入一个字符或字符串 |
| erase | 删除字符串pos位置之后的len个字符 |
| operator+= | 在字符串后追加字符串str |
| c_str | 返回C格式字符串 |
| find | 从字符串中pos位置从前向后找字符c,返回该字符在字符串中的位置 |
| rfind | 从字符串中pos位置从后向前找字符c,返回该字符在字符串中的位置 |
| substr | 在str中从pos位置开始,截取n个字符,然后将其返回 |
1.push_back:在字符串后尾插字符c
void push_back (char c);
- string s1("hello");
- s1.push_back('!');
- cout << s1 << endl; //hello!
2.append:在字符串后追加一个字符串
- string& append (const string& str);//追加str
- string& append (const string& str, size_t subpos, size_t sublen);
- //追加str从subpos位置开始的向后sublen个字符
- string& append (const char* s);//追加字符串s
- string& append (const char* s, size_t n);//追加字符串s的n个字符
- string& append (size_t n, char c);//追加n个c字符
- string s1("hello");
- string s2(" world");
- s1.append(s2); //hello world
- s1.append(s2, 1, 5);//hello worldworld
- s1.append("!!!");//hello worldworld!!!
- s1.append("12345", 3);//hello worldworld!!!123
- s2.append(3, '!');// world!!!
3.insert:在字符串pos位置插入一个字符或字符串
- string& insert (size_t pos, const string& str);
- //在pos位置插入str
- string& insert (size_t pos, const string& str, size_t subpos, size_t sublen);
- //在pos位置插入str的从subpos位置开始的sublen个字符
- string& insert (size_t pos, const char* s);
- //在pos位置插入字符串s
- string& insert (size_t pos, const char* s, size_t n);
- //在pos位置插入字符串s的n个字符
- string& insert (size_t pos, size_t n, char c);
- //在pos位置插入n个字符c
- string s1("012345");
- string s2("xxabxxcd");
- string s3("**");
- s1.insert(1,s3);//0**12345
- s1.insert(3, s2, 0,2);//0**xx12345
- s3.insert(2,"11");//**11
- s3.insert(4, "2234", 3);//**11223
- s3.insert(1, 3, 'x'); //*xxx*11223
4.operator+=:在字符串后追加字符串str
- string& operator+= (const string& str);
- string& operator+= (const char* s);
- string& operator+= (char c);
- string s1("hello");
- string s2("world");
- s1 += s2;//helloworld
- s1 += "123"; //helloworld123
- s1 += '!'; //helloworld123!
在string尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差不多,一般 情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。
5.c_str:返回C格式字符串
const char* c_str() const;
- string s1("hello world");
- const char* pstr = s1.c_str();
- cout << pstr << endl;//hello world
返回一个指向数组的指针,该数组包含一个以null结尾的字符序列(即C字符串),表示字符串对象的当前值。
6.在str中从pos位置开始,截取n个字符,然后将其返回
string substr (size_t pos = 0, size_t len = npos) const;
npos是string里面的一个静态成员变量
static const size_t npos = -1;为size_t类型的最大值,一般用于表示到字符串的末尾。
- string s1("hello world");
- string s2 = s1.substr();
- cout << s2 << endl;//hello world
7.find,rfind:从字符串中pos位置从前(后)向后(前)找字符c,返回该字符在字符串中的位置。
- size_t find (const string& str, size_t pos = 0) const;
- size_t find (const char* s, size_t pos = 0) const;
- size_t find (char c, size_t pos = 0) const;
-
- size_t rfind (const string& str, size_t pos = npos) const;
- size_t rfind (const char* s, size_t pos = npos) const;
- size_t rfind (char c, size_t pos = npos) const;
- string s1("hello,world!!");
- string s2("world");
- cout << s1.find(s2) << endl;//6
- cout << s1.find("world") << endl;//6
- cout << s1.find('!') << endl;//11
- cout << s1.rfind(s2) << endl;//6
- cout << s1.rfind("world") << endl;//6
- cout << s1.rfind('!') << endl;//12
| 函数 | 功能说明 |
|---|---|
| operator+ | 尽量少用,因为传值返回,导致深拷贝效率低 |
| operator>> | 输入运算符重载 |
| operator<< | 输出运算符重载 |
| getline | 获取一行字符串 |
| relational operators | 大小比较 |
string类的其他接口就不一一列举和介绍了,有需要查文档即可。
为了与原来的string类进行区分,我们在命名空间中模拟实现:
- #include
- #include
- using namespace std;
- namespace sss//命名空间
- {
- class string
- {
- public:
- string(const char* str = "")//构造函数
- {}
- string(const string& str)//拷贝构造函数
- {}
- string& operator=(const string& s)//赋值运算符重载函数
- {}
- ~string()//析构函数
- {}
- private:
- char* _str;
- size_t _size;//有效字符个数
- size_t _capacity;//存储有效字符串的空间大小(不包含'\0')
-
- static const size_t npos;//表示字符串末尾
- };
- const size_t string::npos = -1;
- }
1.构造函数
我们一般会用一个常量字符串来进行初始化,因此用const char* str的指针接收。
如果str为空字符串,即_size = 0时,多开辟几个字节的空间,防止后续按capacity倍数扩容时,出现capacity=0的情况。
- string(const char* str = "")//构造函数
- :_size(strlen(str))
- {
- _capacity = _size == 0 ? 3 : _size;
- _str = new char[(_capacity + 1)];//多开一个空间用于存放'\0';
- strcpy(_str, str);
- }
2.析构函数
释放开辟的空间,成员变量置空即可。
- ~string()//析构函数
- {
- delete[] _str;
- _str = nullptr;
- _size = _capacity = 0;
- }
3.拷贝构造函数
我们来调用下方的test1()函数。
- using namespace std;
- namespace sss
- {
- class string
- {
- public:
- string(const char* str = "")//构造函数
- :_size(strlen(str))
- {
- _capacity = _size == 0 ? 3 : _size;
- _str = new char[(_capacity + 1)];//多开一个空间用于存放'\0';
- strcpy(_str, str);
- }
- ~string()//析构函数
- {
- delete[] _str;
- _str = nullptr;
- _size = _capacity = 0;
- }
- private:
- char* _str;
- size_t _size;//有效字符个数
- size_t _capacity;//存储有效字符串的空间大小(不包含'\0')
-
- static const size_t npos;//表示字符串末尾
- };
- const size_t string::npos = -1;
-
- void test1()
- {
- string s1("hello world");
- string s2(s1);
- }
- }
此处发生崩溃,上述string类没有显式定义其拷贝构造函数与赋值运算符重载,此时编译器会合成默认的,当用s1构造s2时,编译器会调用默认的拷贝构造。

调用默认的拷贝构造后,导致的问题是:s1、s2共用同一块内存空间,在释放时同一块空间被释放多次而引起程序崩溃,这种拷贝方式,称为浅拷贝。
浅拷贝:
编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为 还有效,所以当继续对资源进项操作时,就会发生发生了访问违规。
可以采用深拷贝解决浅拷贝问题,即:每个对象都有一份独立的资源,不要和其他对象共享。
深拷贝:
如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供。
先拷贝其大小和容量,再开辟一块新的空间,将其字符串拷贝过去。
- string(const string& s)//拷贝构造函数
- :_size(s._size)
- , _capacity(s._capacity)
- {
- _str = new char[(_capacity + 1)];
- strcpy(_str, s._str);
- }
4.赋值运算符重载函数
新开辟一块和原字符串相等的空间,将字符串拷贝过去,在释放掉其原本指向的空间。
- string& operator=(const string& s)//赋值运算符重载函数
- {
- if (this != &s)//防止出现自己给自己赋值的情况
- {
- char* tmp = new char[(s._capacity + 1)];
- strcpy(tmp, s._str);
- delete[] _str;
- _str = tmp;
- _size = s._size;
- _capacity = s._capacity;
- }
- return *this;
- }
string类中的迭代器可以把它成是一个char* 的指针。
- typedef char* iterator;
- typedef const char* const_iterator;
-
- iterator begin();//返回第一个字符的位置
- iterator end();//返回最后一个字符的下一个位置
- const_iterator begin()const;
- const_iterator end()const;
- iterator begin()
- {
- return _str;
- }
- iterator end()
- {
- return _str + _size;
- }
-
- const_iterator begin()const
- {
- return _str;
- }
- const_iterator end()const
- {
- return _str + _size;
- }
使用演示:
- void test2()
- {
- string s1("hello world");
- string::iterator it = s1.begin();
- while (it != s1.end())
- {
- *it += 1;//const迭代器只能读,不能修改
- cout << *it;
- ++it;
- }
- //输出结果:ifmmp!xpsme
- }
1.大小和容量
- size_t size()const//返回当前字符串的有效个数
- {
- return _size;
- }
- size_t capacity()const//返回当前字符串存储空间的大小
- {
- return _capacity;
- }
-
- bool empty()const//判断字符串是否为空
- {
- return 0 == _size;
- }
2.reserve 和 resize 函数
- void reserve(size_t newCapacity)//预留空间
- {
- // 如果新容量大于旧容量,则开辟空间
- if (newCapacity > _capacity)
- {
- char* str = new char[newCapacity + 1];
- strcpy(str, _str);
-
- // 释放原来旧空间,然后使用新空间
- delete[] _str;
- _str = str;
- _capacity = newCapacity;
- }
- }
-
-
- void resize(size_t newSize, char c = '\0')
- {
- if (newSize > _size)
- {
- // 如果newSize大于底层空间大小,则需要重新开辟空间
- if (newSize > _capacity)
- {
- reserve(newSize);
- }
-
- memset(_str + _size, c, newSize - _size);
- }
- _size = newSize;
- _str[newSize] = '\0';
- }
1.push_back()函数
- void push_back(char c)
- {
- if (_size == _capacity)//判断是否需要扩容
- reserve(_capacity * 2);
- //调用reserve预留空间
- _str[_size++] = c;
- _str[_size] = '\0';
- }
2.insert()函数
- // 在pos位置上插入字符c/字符串str,并返回该字符的位置
- string& insert(size_t pos, char ch)
- {
- assert(pos <= _size);//确保pos合法
- if (_size + 1 > _capacity)
- {
- reserve(_capacity * 2);
- }
-
- size_t end = _size + 1;
- while (end > pos)//将pos位置之后的字符向后移动
- {
- _str[end] = _str[end - 1];
- --end;
- }
- _str[pos] = ch;
- ++_size;
- return *this;
- }
-
- string& insert(size_t pos, const char* str)//方法同上
- {
- assert(pos <= _size);
- size_t len = strlen(str);
- if (_size + len > _capacity)
- reserve(_size + len);
- size_t end = _size + len;
- while (end > pos + len - 1)//将pos位置之后的字符向后移动
- {
- _str[end] = _str[end - len];
- --end;
- }
- strncpy(_str + pos, str, len);
- _size += len;
- return *this;
- }
3.erase()函数
第一种情况删除pos位置后的全部字符,直接将pos位置改为'\0',将_size赋值为pos即可。(pos为字符串的下标)
第二种情况删除pos位置后的部分字符串,将待删除字符串后面的字符串向前移动即可。_size减去删除的长度len。
- string& erase(size_t pos, size_t len = npos)
- {
- //npos表示字符串结束位置
- assert(pos <= _size);
- if (len == npos || pos + len >= _size)
- {
- _str[pos] = '\0';
- _size = pos;
- }
- else
- {
- strcpy(_str + pos, _str + pos + len);
- _size -= len;
- }
- return *this;
- }
4.append函数和 operator+=
append函数直接复用insert即可,即在字符串末尾追加一个字符串。
- void append(const char* str)
- {
- insert(_size, str);
- }
operator+=直接复用push_back 和 appen即可,即分布追加一个字符和字符串。
- string& operator+=(char ch)
- {
- push_back(ch);
- return *this;
- }
- string& operator+=(const char*str)
- {
- append(str);
- return *this;
- }
5.clear函数
清空字符串,直接将有效字符个数_size置为0,再将第一个字符置为'\0',将字符串置为空串。
- void clear()
- {
- _size = 0;
- _str[_size] = '\0';
- }
6.swap函数
直接调用标准库里的swap函数,分布交换其成员变量即可。
- void swap(string& s)
- {
- std::swap(_str, s._str);
- std::swap(_size, s._size);
- std::swap(_capacity, s._capacity);
- }
7.c_str函数
返回c类型的字符串。
- const char* c_str()const
- {
- return _str;
- }
1.operator[]
返回字符串中下标为pos位置的元素。
- char& operator[](size_t pos)
- {
- assert(pos < _size);
- return _str[pos];
- }
-
- const char& operator[](size_t pos)const
- {
- assert(pos < _size);
- return _str[pos];
- }
2.find()函数
- size_t find(char ch, size_t pos = 0)
- {
- assert(pos <= _size);//确保pos合法
- for (size_t i = pos; i < _size; ++i)
- {
- if (_str[i] == ch)
- return i;
- }
- return npos;
- }
-
- size_t find(const char* str, size_t pos = 0)
- {
- assert(pos <= _size);
- char* p = strstr(_str + pos, str);//调用库函数
- if (p == nullptr)
- return npos;
- else
- return p - _str;//得到的元素个数,即为目标字符串开头的下标
- }
字符串比较调用标准库的strcmp函数,其余对已经实现的运算符重载进行复用。
- bool operator>(const string& s)const
- {
- return strcmp(_str, s._str)>0;
- }
-
- bool operator==(const string& s)const
- {
- return strcmp(_str, s._str) == 0;
- }
- bool operator>=(const string& s)const
- {
- return (* this>s || *this == s);
- }
-
- bool operator<(const string& s)const
- {
- return !(* this >= s);
- }
- bool operator<=(const string& s)const
- {
- return !(*this >s);
- }
- bool operator!=(const string& s)const
- {
- return !(*this == s);
- }
流插入:逐个字符输出。
- ostream& operator<<(ostream& _cout, const sss::string& s)
- {
- // 直接cout时, 是将_str当成char*打印的,遇到内部的\0时后序内容就不打印了
- //cout << s._str;
- for (size_t i = 0; i < s.size(); ++i)
- {
- _cout << s[i];
- }
- return _cout;
- }
流提取:
- istream& operator>>(istream& in, string& s)
- {
- s.clear();//清空字符串
- char ch = in.get();//读取一个字符
- char buff[128];//用做缓存数组,避免频繁开辟空间
- size_t i = 0;
- while (ch != ' ' && ch != '\n')//这两个符号为分割符
- {
- buff[i++] = ch;
- if (i == 127)//当数组满了,将字符串写入目标串
- {
- buff[127] = '\0';
- s += buff;
- i = 0;
- }
- }
- if (i != 0)
- {
- buff[i] = '\0';
- s += buff;
- }
- return in;
- }
- #include
- #include
- using namespace std;
- namespace sss
- {
- class string
- {
- public:
- string(const char* str = "")//构造函数
- :_size(strlen(str))
- {
- _capacity = _size == 0 ? 3 : _size;
- _str = new char[(_capacity + 1)];//多开一个空间用于存放'\0';
- strcpy(_str, str);
- }
- string(const string& s)//拷贝构造函数
- :_size(s._size)
- , _capacity(s._capacity)
- {
- _str = new char[(_capacity + 1)];
- strcpy(_str, s._str);
- }
- string& operator=(const string& s)//赋值运算符重载函数
- {
- if (this != &s)
- {
- char* tmp = new char[(s._capacity + 1)];
- strcpy(tmp, s._str);
- delete[] _str;
- _str = tmp;
- _size = s._size;
- _capacity = s._capacity;
- }
- return *this;
- }
- ~string()//析构函数
- {
- delete[] _str;
- _str = nullptr;
- _size = _capacity = 0;
- }
-
- typedef char* iterator;
- typedef const char* const_iterator;
- iterator begin()
- {
- return _str;
- }
- iterator end()
- {
- return _str + _size;
- }
-
- const_iterator begin()const
- {
- return _str;
- }
- const_iterator end()const
- {
- return _str + _size;
- }
-
- size_t size()const
- {
- return _size;
- }
- size_t capacity()const
- {
- return _capacity;
- }
-
- bool empty()const
- {
- return 0 == _size;
- }
-
- void reserve(size_t newCapacity)
- {
- // 如果新容量大于旧容量,则开辟空间
- if (newCapacity > _capacity)
- {
- char* str = new char[newCapacity + 1];
- strcpy(str, _str);
-
- // 释放原来旧空间,然后使用新空间
- delete[] _str;
- _str = str;
- _capacity = newCapacity;
- }
- }
-
- void resize(size_t newSize, char c = '\0')
- {
- if (newSize > _size)
- {
- // 如果newSize大于底层空间大小,则需要重新开辟空间
- if (newSize > _capacity)
- {
- reserve(newSize);
- }
-
- memset(_str + _size, c, newSize - _size);
- }
- _size = newSize;
- _str[newSize] = '\0';
- }
-
- void push_back(char c)
- {
- if (_size == _capacity)
- reserve(_capacity * 2);
-
- _str[_size++] = c;
- _str[_size] = '\0';
- }
- // 在pos位置上插入字符c/字符串str,并返回该字符的位置
- string& insert(size_t pos, char ch)
- {
- assert(pos <= _size);
- if (_size + 1 > _capacity)
- {
- reserve(_capacity * 2);
- }
-
- size_t end = _size + 1;
- while (end > pos)
- {
- _str[end] = _str[end - 1];
- --end;
- }
- _str[pos] = ch;
- ++_size;
- return *this;
- }
- string& insert(size_t pos, const char* str)
- {
- assert(pos <= _size);
- size_t len = strlen(str);
- if (_size + len > _capacity)
- reserve(_size + len);
- size_t end = _size + len;
- while (end > pos + len - 1)
- {
- _str[end] = _str[end - len];
- --end;
- }
- strncpy(_str + pos, str, len);
- _size += len;
- return *this;
- }
-
- string& erase(size_t pos, size_t len = npos)
- {
- assert(pos <= _size);
- if (len == npos || pos + len >= _size)
- {
- _str[pos] = '\0';
- _size = pos;
- }
- else
- {
- strcpy(_str + pos, _str + pos + len);
- _size -= len;
- }
- return *this;
- }
-
- void append(const char* str)
- {
- insert(_size, str);
- }
-
- string& operator+=(char ch)
- {
- push_back(ch);
- return *this;
- }
- string& operator+=(const char* str)
- {
- append(str);
- return *this;
- }
-
- void clear()
- {
- _size = 0;
- _str[_size] = '\0';
- }
-
- void swap(string& s)
- {
- std::swap(_str, s._str);
- std::swap(_size, s._size);
- std::swap(_capacity, s._capacity);
- }
-
- const char* c_str()const
- {
- return _str;
- }
-
- char& operator[](size_t index)
- {
- assert(index < _size);
- return _str[index];
- }
-
- const char& operator[](size_t index)const
- {
- assert(index < _size);
- return _str[index];
- }
-
- size_t find(char ch, size_t pos = 0)
- {
- assert(pos <= _size);
- for (size_t i = pos; i < _size; ++i)
- {
- if (_str[i] == ch)
- return i;
- }
- return npos;
- }
-
- size_t find(const char* str, size_t pos = 0)
- {
- assert(pos <= _size);
- char* p = strstr(_str + pos, str);
- if (p == nullptr)
- return npos;
- else
- return p - _str;
- }
-
- bool operator>(const string& s)const
- {
- return strcmp(_str, s._str) > 0;
- }
-
- bool operator==(const string& s)const
- {
- return strcmp(_str, s._str) == 0;
- }
- bool operator>=(const string& s)const
- {
- return (*this > s || *this == s);
- }
-
- bool operator<(const string& s)const
- {
- return !(*this >= s);
- }
- bool operator<=(const string& s)const
- {
- return !(*this > s);
- }
- bool operator!=(const string& s)const
- {
- return !(*this == s);
- }
-
- private:
- friend ostream& operator<<(ostream& _cout, const sss::string& s);
- friend istream& operator>>(istream& _cin, sss::string& s);
- private:
- char* _str;
- size_t _size;//有效字符个数
- size_t _capacity;//存储有效字符串的空间大小(不包含'\0')
-
- static const size_t npos;//表示字符串末尾
- };
- const size_t string::npos = -1;
-
- ostream& operator<<(ostream& _cout, const sss::string& s)
- {
- // 不能使用这个, 因为string的字符串内部可能会包含\0
- // 直接cout时, 是将_str当成char*打印的,遇到内部的\0时后序内容就不打印了
- //cout << s._str;
- for (size_t i = 0; i < s.size(); ++i)
- {
- _cout << s[i];
- }
- return _cout;
- }
- istream& operator>>(istream& in, string& s)
- {
- s.clear();//清空字符串
- char ch = in.get();//读取一个字符
- char buff[128];//用做缓存数组,避免频繁开辟空间
- size_t i = 0;
- while (ch != ' ' && ch != '\n')//这两个符号为分割符
- {
- buff[i++] = ch;
- if (i == 127)//当数组满了,将字符串写入目标串
- {
- buff[127] = '\0';
- s += buff;
- i = 0;
- }
- }
- if (i != 0)
- {
- buff[i] = '\0';
- s += buff;
- }
- return in;
- }
- }