string大家肯定都会用,那么我们来简单实现下string,并非完全重现string,意思到了就好。
这次就不用声明定义分离了。实现直接放头文件里了,也方便大家看。
目录
一:结构和迭代器
namespace hhh
{ class string
{ public:
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;}
const static size_t npos;//这个你们肯定string里见过
//还有其他成员函数
private:
char* _str;
size_t _size;
size_t _capacity;
};
const size_t string::npos=-1;
}
二:构造 析构 赋值
string(const char* str="") //""里面不用放东西 自带'\0'的
:_size(strlen(str))
,_capacity(_size)
{ _str=new char[_capacity+1];
strcpy(_str,str);
} //构造
void swap(string& s)
{ std::swap(_str,s._str);
std::swap(_size,s._size);
std::swap(_capacity,s._capacity);
}
string(const string&s)
:_str(nullptr)
,_size(0)
,_capacity(0)
{ string tmp(s._str);
swap(tmp);
} //拷贝构造
string& operator=(string tmp) //传引用传参还得先构造个新的tmp 传值直接构造完了 步骤更少
{ swap(tmp);
return *this;
}
~string()
{ delete[] _str;
_str=nullptr;
_size=_capacity=0;
}
三:reserve和resize
void reserve(size_t n)
{ if(n>_capacity)
{ char*tmp=new char[n+1];
strcpy(tmp,_str);
delete[] _str;
_str=tmp;
_capacity=n;
}
}
void resize(size_t n,char ch='\0')
{ if(n<_size) {_str[n]='\0';_size=n;}
else
{ while(_size!=n)
{ _str[_size]=ch;
_size++;
}
_str[n]='\0';
}
}
四:find
char& operator[](size_t pos)
{ assert(pos<_size);
return _str[pos];
}
const char& operator[](size_t pos) const
{ assert(pos<_size);
return _str[pos];
}
size_t find(char ch,size_t pos=0)
{ for(int i=pos;pos<_size;pos++)
{if(_str[i]==ch) return i;}
return npos;
}
size_t find(const char* sub,size_t pos=0)
{ char*p=strstr(_str+pos,sub);
if(p) return p-_str;
else return npos;
}
五:substr
string substr(size_t pos,size_t len=npos)
{ size_t end=pos+len;
string s;
if(len=npos||end>=_size) end=_size;
for(int i=pos;i<end;i++) s+=_str[i]; //+=下面会实现
return s;
}
六:尾插 +=
void push_back(char ch)
{ if(_size==_capacity) reserve(_capacity==0?4:2*_capacity);
_str[_size]=ch;
_size++;
_str[_size]='\0';
}
void append(const char* str)
{ int len=strlen(str);
if(_size+len>_capacity) reserve(_size+len);
strcpy(_str+_size,str);
_size+=len;
}
string& operator+=(char ch)
{ push_back(ch);
return *this;
}
string& operator+=(const char* str)
{ append(str);
return *this;
}
七:insert erase
void insert(int pos,char ch)
{ assert (pos<=_size);
if(_size==_capacity) reserve(_capacity==0?4:2*_capacity);
int end=_size;
while(end>=pos)
{ _str[end]=_str[end-1];
end--;
}
_str[pos]=ch;
_size++;
}
void insert(int pos,const char* str)
{ assert(pod<=_size);
int len=strlen(str);
if(_size+len>_capacity) reserve(_size+len);
int end=pos+len;
while(end>=pos)
{ _str[end]=_str[end-1];
end--;
}
strncpy(_str+pos,str,len);
_size+=len;
}
void erase(int pos,int len=npos)
{ assert(pos<_size);
if(end+len>=_size||len==npos)
{ _str[pos]='\0';
_size=pos;
}
else
{ int begin=pos+len;
while(begin>=_size)
{ _str[begin-len]=_str[begin];
begin++;
}
_size-=len;
}
}
为啥很多地方不用size_t ,因为像end这种头插是有可能减着减着变成-1了,但是无符号啊。另外如果end是int pos是size_t ,符号两边类型不同会发生类型提升 ,所以要么强转int或避开-1,太麻烦了。
八:比较符号
bool operator<(const string& s) const
{
return strcmp(_str, s._str) < 0;
}
bool operator==(const string& s) const
{
return strcmp(_str, s._str) == 0;
}
bool operator<=(const string& s) const
{
return *this < s || *this == s;
}
bool operator>(const string& s) const
{
return !(*this <= s);
}
bool operator>=(const string& s) const
{
return !(*this < s);
}
bool operator!=(const string& s) const
{
return !(*this == s);
}
九:cout cin
ostream& operator<<(ostream&out,const string& s)
{ for(auto ch:s) out<<ch;
return out;
}
istream& operator>>(istream&in,const string&s)
{ s.clear();
char buff[129];//你也可以直接reserve 但是这样可以节省空间 因为buff会自己销毁掉
int i=0;
char ch;
ch=in.get();//不用这个拿不到空格 换行 cin和scanf这方面差不多 get类似getchar
while(ch!=' '&&ch!='\0')
{ buff[i++]=ch;
if(i==128)
{ buff[i]='\0';
s+=buff;
i=0;
}
ch=in.get();
}
if(i!=0)
{ buff[i]='\0';
s+=buff;
}
return in;
}
void clear()
{ _str[0]='\0';
_size=0;
}
十:其他
size_t capacity() const
{
return _capacity;
}
size_t size() const
{
return _size;
}
const char* c_str() const
{
return _str;
}
感谢你看到这,大家共同进步!