移情别恋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;

}



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。