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=s1string&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; //返回首个字符的位置}elsereturn 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;}