1.存储结构
namespace zone
{
class string
{
public:
private: //设置私有,不允许随便访问底层数据
char* _str; //字符串存储空间首地址指针
size_t _size; //当前字符数量
size_t _capaicty; //可用容量
static const size_t npos;
}
const size_t string::nops = -1;//在类外面初始化
}
_str:指向字符串存放的空间的指针
_size:代表当前所存储的有效字符数量
_capacity:代表当前可存储的最大容量
nops:此值设置为 -1,无符号整型转换就是42亿,且此值为const和静态参数具有全局效应,某些函数设置其为缺省参数
2.默认成员函数
注意:在test.cpp文件中 #include“string.h“需要写在 using namespace std; 下方
因为构造函数需要调用iostream中的函数(strlen),而展开iostream需要使用using namespace std,而寻找默认从展开处往上找。
如果#include“string.h“写在 using namespace std上方:
调用strlen时就会从#include“string.h“上方找,会找不到using namespace std,自然无法调用strlen。
2.1构造函数
1.初始化列表
string(const char* str="")// 传的是常量字符串 需要用const :_size(strlen(str)) , _capacity(_size) { _str = new char[_capacity+1];//+1是因为要存“\0" strcpy(_str, str); };
1先得出字符串的长度,初始化size,capacity。
2.用 new 为str开空间。
3.复制字符串。
2.拷贝构造
void swap(string& s) { std::swap(_str, s._str); std::swap(_size, s._size); std::swap(_capacity, s._capacity); } //s2(s1) string(const string& str) //记得加&!!!!!!!!!!!!!! : _str(NULL) ,_size(0) ,_capacity(0) { string tmp(str._str); //调用初始化列表 swap(tmp); } //s2=s1 string&operator=(string str) //传值传参,调用拷贝构造(上文) { swap(str); //这里将s1和str交换,出作用域后,将原来s1里的内容析构 return *this; }
2.2 析构函数
~string() { delete[] _str; _str = NULL; _size = _capacity = 0; }
因为我们使用 new[ ] 申请,所以对应的释放是 delete[ ] ,这里需要注意!
3.容量操作函数
3.1.reserve(设置空间大小)
void reserve(size_t num) { if (num >= _capacity) //默认为扩容 { char* str = new char[num + 1]; //+1表示为\0留空间 strcpy(str, _str); delete[] _str; _str = str; _capacity = num; } }
3.2 resize(重新设置string的长度)
void resize(size_t n, char ch = '\0') { if (n <= _size) //小于size,相当于删除 { _str[n] = '\0'; _size = n; } else //大于size,相当与添加 { reserve(n); while (_size < n) { _str[_size] = ch; _size++; } _str[_size] = '\0'; } }
3.3 获取size和capacity
size_t size() { return _size; } size_t capacity() { return _capacity; }
4.字符串访问函数
4.1[]
char& operator[](size_t pos) { assert(pos < _size); return _str[pos]; }
实现数组的访问模式
4.2迭代器
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; }
通过返回指针的方式实现迭代器的功能
5.插入类函数
5.1 push_back(尾插字符)
void push_back(char str) //这里可以不用const,因为是非指针的拷贝构造,str改变不会影响原字符的改变 { if (_size == _capacity) reserve(_capacity * 2); _str[_size] = str; _size++; _str[_size] = '\0'; //记得有\0 }
5.2 append (尾插字符串)
void append(const char* str) //这里需要用const,因为是指针的拷贝构造(值拷贝),新指针也指向原字符串(常量),不能改变 { if (_size+ strlen(str) > _capacity) reserve(_capacity+strlen(str)); strcpy(_str + _size, str); //从最末尾处开始复制str _size += strlen(str); }
5.3 insert(在某一位置插入字符或字符串)
void insert(size_t pos, char str) //插入字符 { assert(pos <= _size); if (_size == _capacity) { reserve(_capacity == 0 ? 4 : _capacity * 2); } int end = _size; while (end >= (int)pos) //需要强制类型转换成int,否则会因为类型提升倒置死循环 { _str[end + 1] = _str[end]; end--; } _str[pos] = str; _size++; } void insert(size_t pos,const char* str) //插入字符串 { int len = strlen(str); if (_size == _capacity) { reserve(_capacity == 0 ? len : _capacity+len); } int end = _size; while (end >= (int)pos) //需要强制类型转换成int,否则会因为类型提升倒置死循环 { _str[end + len] = _str[end]; end--; } strncpy(_str + pos,str,len);//使用strncpy控制复制区间 _size = _size + len; }
6.删除类函数(erase)
void erase(size_t pos, size_t len = npos) //从pos位置开始,删除len个字符 { assert(pos < _size); if (len == npos || pos + len >= _size) //从pos处开始删完 或者 超出_size也是删完 { _str[pos] = '\0'; _size = pos; } else { size_t flag = pos + len; while (flag <= _size) { _str[flag - len] = _str[flag]; ++flag; } _size -= len; } }
7.运算符重载
7.1 +=
string& operator+=(char str)//字符 { push_back(str); return *this; } string& operator+=(const char* str) //字符串,记得加const { append(str); return *this; }
7.2 逻辑判断运算符
bool operator<( const string& s) { return strcmp(_str, s._str) < 0; } bool operator==(const string& s) { return strcmp(_str, s._str) == 0; } bool operator<=(const string& s) { return *this < s || *this == s; } bool operator>(const string& s) { return !(*this <= s); } bool operator>=(const string& s) { return !(*this < s); } bool operator!=(const string& s) { return !(*this == s); }
string类的比较
8.查找和提取函数
8.1查找函数 find
size_t find(char ch, size_t pos = 0) //查找字符, 提供缺省值,可以控制在何处开始查找 { for (size_t i = pos; i < _size; i++) { if (_str[i] == ch) return i; } return pos; } size_t find(const char* str, size_t pos = 0) //查找字符串,提供缺省值,可以控制在何处开始查找 { const char* p = strstr(_str+pos, str); if (p) { return p - _str; //返回首个字符的位置 } else return npos; }
8.2 提取函数 substr
string substr(size_t pos, size_t len = npos) //从pos位置开始取len个字符 { string s; size_t end = pos + len; if (len == npos || pos + len > _size) { len = _size - pos; end = _size; } s.reserve(len); for (size_t i = pos; i < end; i++) { s += _str[i]; } return s; //传值返回,调用拷贝构造(深拷贝) }
9.流操作(要写在class外,namespace内)
9.1流插入
ostream& operator<<(ostream& out, const string& s) { for (auto ch :s) { out << ch; } return out; }
9.2 流提取
istream& operator<<(istream& in, string& s) { s.clear(); //需要先清空字符串,不然+=会调用尾插 到之前的字符串 char ch; ch=in.get(); //用于读入空格 while (ch != ' ' && ch != '\n') { s += ch; ch = in.get(); } return in; }