📌string的模拟实现
😊本文为小碗里原创,CSDN首发
📅发布时间:2002/3/19
🙌欢迎大家👍点赞❤收藏✨加关注
✒本文大约3100词左右
🙏笔者水平有限,如有错误,还望告诉笔者,万分感谢!
🚩有什么问题也可在评论区一起交流哦!
文章目录
🎉前言
🎉模拟实现
👂一.主干结构
#include<iostream>
//平时练习可以全部展开,命名污染可忽略
using namespace std;
//自己模拟实现的string要与标准库里的string区别
//故模拟实现的string放在自己的命名空间
namespace S
{
class string
{
public:
//成员函数
private:
//成员变量
char* _str; //字符串
int _size; //当前有效字符个数(不含'\0')
int _capacity; //有效字符容量(不含'\0')
public:
static const size_t npos = -1;
//const修饰的静态的成员变量可以在类里给缺省值
//但非const修饰的成员变量只能在类外初始化
};
}
👂二.成员函数
🥩系列一
1.构造函数
string(const char* str = "")//默认缺省值为'\0'
:_str(nullptr), _size(strlen(str)), _capacity(_size)
{
_str = new char[_capacity + 1];//为'\0'多开一个空间
strcpy(_str, str);
}
2.析构函数
~string()
{
//当_str不为nullptr时释放空间
if (_str)
{
delete[] _str;
_str = nullptr;
_size = _capacity = 0;
}
}
3.拷贝构造函数(深拷贝)
//写法一:1.0版本
string(const string& s)
:_str(nullptr), _size(s._size), _capacity(s._capacity)
{
_str = new char[_capacity + 1];//为'\0'多开一个空间
strcpy(_str, s._str);
}
//写法二:2.0版本(分析如下图)
string(const string& s)
:_str(nullptr),_size(s._size),_capacity(s._capacity)
//_str必须初始化为nullptr
{
//复用构造函数开空间,且tmp为局部变量,之后有析构函数销毁
string tmp(s._str);
std::swap(_str, tmp._str);
}
//这里也可用我们自己实现的swap成员函数,它的定义在下文给出
//写法三:
string(const string& s)
:_str(nullptr), _size(0), _capacity(0)
{
string tmp(s._str);
swap(tmp);
}
图 1 图1 图1
4.赋值运算符重载
//写法一:1.0版本
string& operator=(const string& s)
{
if (this != &s)//避免自己给自己赋值
{
int len = strlen(s._str);
//避免new抛异常,而_str却被释放
char* tmp = new char[len + 1];
strcpy(tmp, s._str);
delete[] _str;
_str = tmp;
_capacity = _size = len;
}
//函数调用完成后,*this没有被销毁,故采用引用返回,减少拷贝
return *this;
}
也许你们的写法如下:
string& operator=(const string& s)
{
if (this != &s)
{
int len = strlen[s._str];
//假如new失败了,既没有开新的空间,还把_str释放了
delete[] _str;
_str = new char[len + 1];
strcpy(_str, s._str);
_capacity = _size = len;
}
return *this;
}
细节决定成败…
//写法二:2.0版本(分析如图2)
string& operator=(string s)//注意,这里不是引用传参,传值传参调用拷贝构造函数
{
swap(s);
return *this;
}
//交换两个string类对象(也是一个成员函数,默认第一个形参是this指针)
void swap(string& s)
{
//用全局的swap
std::swap(s._str, _str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
图 2 图2 图2
🥩系列二
1.增容 reserve
void reserve(size_t n)//n:要增到的容量大小
{
if (n > _capacity)
{
char* tmp = new char[n + 1];//为'\0'多开一个空间
strcpy(tmp, _str);
delete[] _str;
_str = tmp;
_capacity = n;
}
}
2.设置内存大小 resize
void resize(size_t n, char ch = '\0')
{
if (n > _capacity)
{
//开辟n+1个空间,第n+1个空间的下标是n
reserve(n);
memset(_str + _size, ch, n - _size);
_size = n;
_str[_size] = '\0';
}
else
{
_str[n] = '\0';
_size = n;
}
}
3.插入字符 insert
//分析如图3
string& insert(size_t pos, char ch)
{
//断言(要引头文件#include<assert.h>)
assert(pos <= _size);
if (_size == _capacity)
{
//_capacity可能为0
reserve(_capacity == 0 ? 4 : _capacity * 2);
}
size_t end = _size;//_size位置是'\0'
while (end > pos)
{
_str[end + 1] = _str[end];
end--;
}
_str[end] = ch;
_size++;
return *this;
}
图 3 图3 图3
4.插入字符串 insert
string& insert(size_t pos,const char* s)
{
//断言
assert(&& pos <= _size);
size_t len = strlen(s);
if (_size == _capacity)
{
//会多开辟一个空间
reserve(_size + strlen(s));
}
size_t end = _size;
while (end>pos)
{
_str[end + len] = _str[end];
end--;
}
//限定拷贝字符的长度
strncpy(_str + pos, s, len);
_size += len;
return *this;
}
5.尾插字符 push_back
void push_back(char ch)
{
insert(_size, ch);
}
6.尾插字符串 append
void append(const char* s)
{
insert(_size, s);
}
细节🤔:
int main()
{
my_string::string s1("lllll");
s1.insert(2, "sss").insert(3, "ddd");
return 0;
}
7.+=
string& operator+=(char ch)
{
//复用
push_back(ch);
return *this;
}
string& operator+=(const char* s)
{
//复用
append(s);
return *this;
}
7.字符查找 find
size_t find(char ch)
{
for (size_t i = 0; i < _size; i++)
{
if (_str[i] == ch)
{
return i;
}
}
//npos:无符号整型的最大值,static const size_t npos = -1;
return npos;
}
8.字符串查找 find
//从pos位置开始查找
size_t find(const char* s,size_t pos = 0)
{
//char* strstr(const char *str1, const char *str2)
//str2是否是str1的字串
//如果是则返回第一个字串的起始地址,否则返回nullptr
const char* tmp = strstr(_str + pos, s);
if (tmp == nullptr)
{
return npos;
}
else
{
return tmp - _str;//返回下标
}
}
9.字符(串)擦除 erase
string& erase(size_t pos = 0, size_t n=npos)
{
assert(pos < _size);
if (n == npos || pos + n >= _size)
{
_str[pos] = '\0';
_size = pos;
}
else
{
//直接往前覆盖
strcpy(_str + pos, _str + pos + n);
/*int end = pos;
while (end + n < _size)
{
_str[end] = _str[end + n];
end++;
}*/
_size -= n;
}
return *this;
}
10.清除 clear
//清除内容,不释放空间
void clear()
{
_str[0] = '\0';
_size = 0;
}
🥩系列三
1.operator[]
//用于支持修改
char& operator[](size_t pos)
{
assert(pos<_size && pos>=0)
return _str[pos];
}
//用于支持访问
const char& operator[](size_t pos) const//类成员变量不会被修改,加上const
{
assert(pos < _size && pos>=0);
return _str[pos];
}
2.c_str
//获取string类里的字符串
const char* c_str() const
{
return _str;
}
3.size
size_t size()
{
return _size;
}
🥩系列四(迭代器)
typedef char* iterator;
typedef const char* const_iterator;
const_iterator begin() const
{
return _str;
}
const_iterator end() const
{
return _str + _size;
}
iterator begin()
{
return _str;
}
iterator end()
{
return _str + _size;
}
👂三.非成员函数
系列四(关系运算符)
1.operator>
//卷王写法:
bool operator>(const S::string& s1, const S::string& s2)
{
size_t i = 0;
while (i < s1.size() && i < s2.size())
{
//用[]访问类成员私有变量
if (s1[i] < s2[i])
{
return false;
}
else
{
i++;
}
}
return s1.size()>i ? true : false;
//eg: asd asd -> false
// asd asdf -> false
// asdf asd -> true -> s1.size()>i
}
//摆王写法:
bool operator>(const S::string& s1, const S::string& s2)
{
return strcmp(s1.c_str(), s2.c_str()) > 0;
}
2.operator==
//卷王写法:
bool operator==(const S::string& s1, const S::string& s2)
{
size_t i = 0;
while (i < s1.size() && i < s2.size())
{
if (s1[i] != s2[i])
{
return false;
}
else
{
i++;
}
}
if (i == s1.size() && i == s2.size())
{
return true;
}
else
{
return false;
}
}
//摆王写法:
bool operator==(const S::string& s1, const S::string& s2)
{
return strcmp(s1.c_str(),s2.c_str()) == 0;
}
[以下皆可复用]
3.operator>=
bool operator>=(const S::string& s1, const S::string& s2)
{
return s1 > s2 || s1 == s2;
}
4.operator<
bool operator<(const S::string& s1, const S::string& s2)
{
return !(s1 >= s2);
}
5.operator<=
bool operator<=(const S::string& s1, const S::string& s2)
{
return !(s1>s2);
}
6.operator!=
bool operator!=(const S::string& s1, const S::string& s2)
{
return !(s1 == s2);
}
🥩系列五
1.operator<<
ostream& operator<<(ostream& out, const string& s)
{
for (size_t i = 0; i < s.size(); ++i)
{
//[]支持访问私有
out << s[i];
}
//范围for
/*for (auto c : s)
{
out << c;
}*/
}
2.operator>>
istream& operator>>(istream& in, string& s)
{
s.clear();
char ch = in.get();
while (ch != '\n')
{
s += ch;
ch = in.get();
}
return in;
}
🎉完整代码
namespace S
{
class string
{
public:
typedef char* iterator;
typedef const char* const_iterator;
const_iterator begin() const
{
return _str;
}
const_iterator end() const
{
return _str + _size;
}
iterator begin()
{
return _str;
}
iterator end()
{
return _str + _size;
}
//构造函数
string(const char* str = "")
:_str(nullptr), _size(strlen(str)), _capacity(_size)
{
_str = new char[_capacity + 1];
strcpy(_str, str);
}
//析构函数
~string()
{
//当_str不为nullptr时释放空间
if (_str)
{
delete[] _str;
_str = nullptr;
_size = _capacity = 0;
}
}
string(const string& s)
:_str(nullptr), _size(0), _capacity(0)
{
string tmp(s._str);
swap(tmp);
}
//赋值运算符重载
//现代写法
void swap(string& s)
{
std::swap(s._str, _str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
string& operator=(string s)
{
swap(s);
return *this;
}
void reserve(size_t n)
{
if (n > _capacity)
{
char* tmp = new char[n + 1];
strcpy(tmp, _str);
delete[] _str;
_str = tmp;
_capacity = n;
}
}
string& insert(size_t pos, char ch)
{
assert(pos >= 0 && pos <= _size);
if (_size == _capacity)
{
//_capacity可能为0
reserve(_capacity == 0 ? 4 : _capacity * 2);
}
size_t end = _size;
while (end > pos)
{
_str[end + 1] = _str[end];
end--;
}
_str[end] = ch;
_size++;
return *this;
}
string& insert(size_t pos, const char* s)
{
assert(pos >= 0 && pos <= _size);
size_t len = strlen(s);
if (_size == _capacity)
{
reserve(_size + strlen(s));
}
size_t end = _size;
while (end>pos)
{
_str[end + len] = _str[end];
end--;
}
//限定拷贝字符的长度
strncpy(_str, s, len);
_size += len;
return *this;
}
void push_back(char ch)
{
insert(_size, ch);
}
void append(const char* s)
{
insert(_size, s);
}
string& operator+=(char ch)
{
push_back(ch);
return *this;
}
string& operator+=(const char* s)
{
append(s);
return *this;
}
void resize(size_t n, char ch = '\0')
{
if (n > _capacity)
{
reserve(n);
memset(_str + _size, ch, n - _size);
_size = n;
_str[_size] = '\0';
}
else
{
_str[n] = '\0';
_size = n;
}
}
size_t find(char ch)
{
for (size_t i = 0; i < _size; i++)
{
if (_str[i] == ch)
{
return i;
}
}
return npos;
}
//从pos位置开始查找
size_t find(const char* s,size_t pos = 0)
{
//char* strstr(const char *str1, const char *str2)
char* tmp = strstr(_str + pos, s);
if (tmp != nullptr)
{
return tmp - _str;
}
else
{
return npos;
}
}
string& erase(size_t pos = 0, size_t n=npos)
{
assert(pos >= 0 && pos < _size);
if (n == npos || pos + n >= _size)
{
_str[pos] = '\0';
_size = pos;
}
else
{
strcpy(_str + pos, _str + pos + n);
_size -= n;
}
return *this;
}
//用于支持修改
char& operator[](size_t pos)
{
assert(pos < _size && pos >= 0);
return _str[pos];
}
//用于支持访问
const char& operator[](size_t pos) const//类成员变量不会被修改,加上const
{
assert(pos < _size && pos >= 0);
return _str[pos];
}
char* c_str() const
{
return _str;
}
void clear()
{
_str[0] = '\0';
_size = 0;
}
size_t size() const
{
return _size;
}
private:
char* _str;
int _size;
int _capacity;
public:
static const size_t npos = -1;
};
}
bool operator>(const S::string& s1, const S::string& s2)
{
size_t i = 0;
while (i < s1.size() && i < s2.size())
{
//用[]访问类成员私有变量
if (s1[i] < s2[i])
{
return false;
}
else
{
i++;
}
}
return s1.size()>i ? true : false;
}
bool operator==(const S::string& s1, const S::string& s2)
{
size_t i = 0;
while (i < s1.size() && i < s2.size())
{
if (s1[i] != s2[i])
{
return false;
}
else
{
i++;
}
}
if (i == s1.size() && i == s2.size())
{
return true;
}
else
{
return false;
}
}
bool operator>=(const S::string& s1, const S::string& s2)
{
return s1 > s2 || s1 == s2;
}
bool operator<(const S::string& s1, const S::string& s2)
{
return !(s1 >= s2);
}
bool operator<=(const S::string& s1, const S::string& s2)
{
return !(s1>s2);
}
bool operator!=(const S::string& s1, const S::string& s2)
{
return !(s1 == s2);
}
ostream& operator<<(ostream& out, const string& s)
{
for (size_t i = 0; i < s.size(); ++i)
{
//[]支持访问私有
out << s[i];
}
}
istream& operator>>(istream& in, string& s)
{
s.clear();
char ch = in.get();
while (ch != '\n')
{
s += ch;
ch = in.get();
}
return in;
}
🎶练习
#include<iostream>
#include<assert.h>
#include<string>
using namespace std;
namespace S
{
class string
{
public:
typedef char* iterator;
typedef const char* const_iterator;
const_iterator begin() const
const_iterator end() const
iterator begin()
iterator end()
string(const char* str = "")
~string()
string& operator=(string s)
void reserve(size_t n)
string& insert(size_t pos, char ch)
string& insert(size_t pos, const char* s)
void push_back(char ch)
void append(const char* s)
string& operator+=(char ch)
string& operator+=(const char* s)
void resize(size_t n, char ch = '\0')
size_t find(char ch)
size_t find(const char* s,size_t pos = 0)
string& erase(size_t pos = 0, size_t n=npos)
char& operator[](size_t pos)
const char& operator[](size_t pos) const
char* c_str() const
void clear()
size_t size() const
private:
char* _str;
int _size;
int _capacity;
public:
static const size_t npos = -1;
};
}
bool operator>(const S::string& s1, const S::string& s2)
bool operator==(const S::string& s1, const S::string& s2)
bool operator>=(const S::string& s1, const S::string& s2)
bool operator<(const S::string& s1, const S::string& s2)
bool operator<=(const S::string& s1, const S::string& s2)
bool operator!=(const S::string& s1, const S::string& s2)
ostream& operator<<(ostream& out, const string& s)
istream& operator>>(istream& in, string& s)
string& operator+=(const char* s)
void resize(size_t n, char ch = '\0')
size_t find(char ch)
size_t find(const char* s,size_t pos = 0)
string& erase(size_t pos = 0, size_t n=npos)
char& operator[](size_t pos)
const char& operator[](size_t pos) const
char* c_str() const
void clear()
size_t size() const
private:
char* _str;
int _size;
int _capacity;
public:
static const size_t npos = -1;
};
}
bool operator>(const S::string& s1, const S::string& s2)
bool operator==(const S::string& s1, const S::string& s2)
bool operator>=(const S::string& s1, const S::string& s2)
bool operator<(const S::string& s1, const S::string& s2)
bool operator<=(const S::string& s1, const S::string& s2)
bool operator!=(const S::string& s1, const S::string& s2)
ostream& operator<<(ostream& out, const string& s)
istream& operator>>(istream& in, string& s)
> 最后,笔者想说的是,string的成员函数还有很多,这里模拟实现的都是string中较为常用的,其他的函数读者有兴趣的话可以自己下去模拟实现一下,当然也可与笔者一起交流学习!😁🤪😆