移情别恋c++ ദ്ദി˶ー̀֊ー́ ) ——5.string(模拟实现)
码码生的 2024-08-18 11:35:01 阅读 86
1.存储结构
<code>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.初始化列表
<code>string(const char* str="")// 传的是常量字符串 需要用constcode>
:_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;
}
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。