2.数据删除
对于数据的删除,一般来说就是尾删和在任意位置删除。
1. pop_back
尾删很简单,我们只需要把最后一个有效字符的值替换成\0,然后更改_size即可
void pop_back() { _str[--_size] = '\0'; }
2. erase
erase的实现分为两种情况
- 当删除的长度大于pos位置之后的长度,或者为npos时,直接删除后续所有的值
- 当len小于后续长度时,挪动数据
string& erase(size_t pos, size_t len = npos) { assert(pos < _size); if (len == npos || pos + len >= _size) { _str[pos] = '\0'; _size = 0; } //挪动数据 else { strcpy(_str + pos, _str + pos + len); _size -= len; } return *this; }
3.数据查找
find:从pos位置开始查找字符或字符串,找到返回下标,找不到返回npos
1. 查找字符
size_t find(size_t pos, char ch) { assert(pos < _size); for (size_t i = 0; i < _size; ++i) { if (_str[i] == ch) return i; } return npos; }
2. 查找字符串
对于字符串的查找我们可以借用strstr函数实现
size_t find(size_t pos, const char* str) { assert(pos < _size); const char* ptr = strstr(_str, str); if (ptr == nullptr) { return npos; } else { return ptr - _str; } }
注:修改是建立在查找上的,所以这里就不专门讲解了
7.流插入和流提取
对于流插入和流提取的重载,我们在日期类的时候就已经讲过,不能重载成成员函数,如果重载成成员函数会导致this指针抢占第一个位置。所以需要重载成全局函数,然后在类里面设成友元。
1. 流插入
ostream& operator<<(ostream& _cout, const zht::string& s) { for (size_t i = 0; i < s.size(); i++) { _cout << s[i]; } return _cout; }
2. 流提取
对于流提取,我们使用cin或者scanf是没有办法拿到空格和\0的,所以这里需要使用get函数来拿到
istream& operator>>(istream& _cin, zht::string& s) { s.clear(); char ch = _cin.get(); while (ch != ' ' && ch != '\0') { s += ch; ch = _cin.get(); } return _cin; }
但是,对于上述的情况,如果需要扩容的话,会导致频繁扩容,所以我们在这里使用一个临时数组来存放,然后统一尾插到string中去。
istream& operator>>(istream& _cin, zht::string& s) { s.clear(); char buff[128] = { '\0' }; size_t i = 0; char ch = _cin.get(); while (ch != ' ' && ch != '\0') { if (i == 127) { s += buff; i = 0; } buff[i++] = ch; ch = _cin.get(); } if (i > 0) { buff[i] = '\0'; s += buff; } return _cin; }
8.其他接口
在上文中,我们提到了一个swap函数,这个swap函数在使用的时候,形参只有一个,这个swap函数就是在string类中重载的一个函数。
为什么要在string里面重新重载一个swap函数呢?
这是因为算法库里面实现的swap函数是一个模板
可以看到,无论对于什么类型,他都会无脑的拷贝构造,这样其实对于string这种使用new在堆上开辟空间的类效率是不高的,所以需要在类内重新写一个swap函数,将类内的成员变量进行交换即可,这样就能省去new和delete的消耗。
void swap(string& s) { std::swap(_str, s._str); std::swap(_size, s._size); std::swap(_capacity, s._capacity); }
2. c_str
对于Linux操作系统,它是使用C语言写的,所以它的系统接口也都是C形式的接口,而不支持string,所以我们在进行系统调用的时候,需要将string转换成C字符串的形式传参。c_str就是将string类返回成C字符串形式。
char* c_str() { return _str; } const char* c_str() const { return _str; }
载一个swap函数呢?
这是因为算法库里面实现的swap函数是一个模板
[外链图片转存中…(img-CP2s20jF-1681724759328)]
可以看到,无论对于什么类型,他都会无脑的拷贝构造,这样其实对于string这种使用new在堆上开辟空间的类效率是不高的,所以需要在类内重新写一个swap函数,将类内的成员变量进行交换即可,这样就能省去new和delete的消耗。
void swap(string& s) { std::swap(_str, s._str); std::swap(_size, s._size); std::swap(_capacity, s._capacity); }
2. c_str
对于Linux操作系统,它是使用C语言写的,所以它的系统接口也都是C形式的接口,而不支持string,所以我们在进行系统调用的时候,需要将string转换成C字符串的形式传参。c_str就是将string类返回成C字符串形式。
char* c_str() { return _str; } const char* c_str() const { return _str; }