目录
一.成员变量
先来看看string的内部结构
所以我们要定义的三个成员变量分别是str,size,capacity
private:
size_t _size;
size_t _capacity;
char* _str;
二.成员函数
1.(Constructor)
主要实现三种常用构造
string(const char* str="") // 利用缺省值包含空
:_size(strlen(str))
, _capacity(_size)
, _str(new char[_capacity + 1])
{
memcpy(_str, str,_size+1);
}
string(const string& str) //拷贝构造
{
_str = new char[str._capacity+1];
_capacity = str._capacity;
_size = str._size;
memcpy(_str, str._str, str._size + 1);
}
这里需要注意初始化列表是按照声明顺序初始化的,并且开空间和拷贝的时候,多一个位置用来存放字符串结尾标志\0。
2.(destructor)
~string()
{
delete[] _str;
_str = nullptr;
_size = _capacity = 0;
}
3.Capacity:
①. c_str size capacity
由于有时候我们需要用到成员变量,但是这些成员变量又是私有的,我们需要写一个公共成员函数来返回他们的值。
const char* c_str() const
{
return _str;
}
size_t size() const
{
return _size;
}
size_t capacity() const
{
return _capacity;
}
②.empty
判空只需要检查size的大小是不是0
bool empty()const
{
return _size == 0;
}
③. reserve
由于string::reserve是不缩容的,所以只有新开的空间大于原空间的时候,我们才进行处理,思路就是先开辟新的空间,再把老空间的数据拷贝到新空间,最后释放老空间。
void reserve(size_t capacity)
{
if (capacity > _capacity) //不缩容
{
char* tmp = new char[capacity+1]; //多开\0
memcpy(tmp, _str, _size+1); //\0也要拷贝
_capacity = capacity;
delete[] _str;
_str = tmp;
}
}
④.resize
与reserve不同的是,resize会对开辟的空间进行初始化,并且resize不仅会改变capacity的大小,也会改变size的大小,reserve只会改变capacity的大小。最后始终要记得结尾有\0
void resize(size_t n, char c = '\0')
{
if (n < _size)
{
_size = n;
_str[_size] = '\0';
}
else
{
reserve(n);
for (size_t i = _size; i < n; i++)
{
_str[i] = c;
}
_size = n;
_str[_size] = '\0';
}
}
⑤.clear
直接在字符串开头放\0,更新一下size就完了。
void clear()
{
_str[0] = '\0';
_size = 0;
}
4.Iterators:
①.begin
begin()函数有两种重载,一种是对于const对象,一种是对于普通对象。
iterator begin()
{
return _str;
}
iterator begin() const
{
return _str;
}
②.end
end和begin一样,同样拥有两种重载,这里要注意的是end返回的是\0的地址。
iterator end() // 返回\0的地址
{
return _str + _size;
}
iterator end() const // 返回\0的地址
{
return _str + _size;
}
5.Element access:
①.operator[]
这里需要检查pos位置是否合理。
char& operator[](size_t pos)
{
assert(pos < _size);
return _str[pos];
}
6.Modifiers:
①.append
这里需要注意的是扩容的问题
void append(const char* str)
{
int len = strlen(str);
if (_size + len > _capacity)
{
//至少扩容到_size+str的长度
reserve(_size + len);
}
for (size_t i = 0; i < len; i++)
{
_str[_size++] = str[i]; //更新_size
}
_str[_size] = '\0';
}
void append(string& str)
{
if (_size + str._size > _capacity)
{
//至少扩容到_size+str的长度
reserve(_size + str._size);
}
for (size_t i = 0; i < str._size; i++)
{
_str[_size++] = str[i]; //更新_size
}
_str[_size] = '\0';
}
③.push_back
这里需要注意capacity为0的时候,2*capacity也是0,所以可以分开处理一下
void push_back(const char c) //尾插一个C字符
{
if (_size == _capacity)
{
reserve(_capacity==0?4:2 * _capacity); // _capacity为0的话,2*_capacity为0
}
_str[_size++] = c; //更新_size
_str[_size] = '\0'; //扩完容+'\0'
}
④. operator+=
可以复用写过的函数
string& operator+=(const char* str) //这里的string是namespace内的
{
append(str);
return *this;
}
string& operator+=(const char c)
{
push_back(c);
return* this;
}
⑤.insert
一种是字符串,一种是字符,两种重载。
void insert(size_t pos, const char* str)
{
assert(pos<=_size);
size_t len = strlen(str);
if (len + _size > _capacity)
{
reserve(len + _size);
}
int end = _size;
while (end >= (int)pos)
//如果pos为0 end最后一次变成-1,整形提升变成42e,无限循环
{
_str[end + len] = _str[end];
end--;
}
for (size_t i = 0; i < len; i++)
{
_str[pos++] = str[i];
}
_size += len;
_str[_size] = '\0';
}
void insert(size_t pos, size_t n,const char c)
{
assert(pos <= _size);
if (_size + n > _size)
{
reserve(_size + n);
}
int end = _size;
while (end >= (int)pos)
//如果pos为0 end最后一次变成-1,整形提升变成42e,无限循环
{
_str[end + n] = _str[end];
end--;
}
for (size_t i = 0; i < n; i++)
{
_str[pos++] = c;
}
_size += n;
_str[_size] = '\0';
}
⑥.erase
有两种情况,如果len==npos或者是pos+len>=size说明要删完,我们直接在起始位置放\0,再更新size就完了。但是还有一种情况是没删完,我们就需要挪动字符,再更新size。
void erase(size_t pos, size_t len =npos)
{
assert(pos <= _size);
if (len == npos || pos + len >= _size)
{
_str[pos] = '\0';
_size = pos;
_str[_size] = '\0';
}
else
{
size_t end=pos+len;
while (end <= _size)
{
_str[pos++] = _str[end++];
}
_size -= len;
_str[_size] = '\0';
}
}
⑦.swap
可以和operator=配合使用
void swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
7.String operations:
①.find
这里返回的是下标 两个指针相减就是下标
size_t find(const char* str, size_t pos = 0) const
{
assert(pos < _size);
const char*p=strstr(_str, str);
if(p)
{
return p-_str;
}
else
return npos;
}
②.substr
string substr(size_t pos = 0, size_t len = npos) const
{
assert(pos < _size);
size_t n = len;
if (len == npos || len + pos > _size)
{
n = _size - pos;
}
string tmp;
tmp.reserve(n);
for (size_t i = pos; i < n; i++)
{
tmp += _str[i];
}
return tmp;
}
8.relational operators:
bool operator> (const string& s)
{
size_t i = 0;
while (i<_size && i<s.size())
{
if (_str[i] > s[i])
return 1;
else if (_str[i] < s[i])
return 0;
else
i++;
}
if (i == _size && i != s.size())
return 0;
else if (i == _size && i == s.size())
return 0;
else
return 1;
}
bool operator< (const string& s)
{
size_t i = 0;
while (i < _size && i < s.size())
{
if (_str[i] > s[i])
return 0;
else if (_str[i] < s[i])
return 1;
else
i++;
}
if (i == _size && i != s.size())
return 1;
else if (i == _size && i == s.size())
return 0;
else
return 0;
}
bool operator>= (const string& s)
{
size_t i = 0;
while (i < _size && i < s.size())
{
if (_str[i] > s[i])
return 1;
else if (_str[i] < s[i])
return 0;
else
i++;
}
if (i == _size && i != s.size())
return 0;
else if (i == _size && i == s.size())
return 1;
else
return 1;
}
bool operator<= (const string& s)
{
size_t i = 0;
while (i < _size && i < s.size())
{
if (_str[i] > s[i])
return 0;
else if (_str[i] < s[i])
return 1;
else
i++;
}
if (i == _size && i != s.size())
return 1;
else if (i == _size && i == s.size())
return 1;
else
return 0;
}
bool operator== (const string& s)
{
if (_size == s._size)
{
size_t i= 0;
while (i < _size)
{
if (_str[i] != s[i])
{
return 0;
}
i++;
}
return 1;
}
return 0;
}
bool operator!= (const string& s)
{
if (_size == s._size)
{
size_t i = 0;
while (i < _size)
{
if (_str[i] == s[i])
{
i++;
}
else return 1;
}
return 0;
}
return 1;
}
9.operator<<和operator>>
operator<<是按size大小来打印,而不是字符串的结束标志\0
operator>>如果用cin输入,会自动跳过空格和换行,所以用cin.get
ostream& operator<<(ostream& out, const lsh::string& str) // <<是全部输出,用c_str会遇到\0停止
{
for (size_t i = 0; i < str.size(); i++)
{
out << str[i];
}
out << endl;
return out;
}
istream& operator>>(istream& in, lsh::string& str) // <<是全部输出,用c_str会遇到\0停止
{
str.clear();
char ch=0;
while (ch == ' ' || ch == '\n')
{
ch = in.get();
}
char buff[128] = {0}; //用栈,尽量少扩容
ch=in.get();//cin自动跳过\n和' '
int i=0;
while (ch != ' ' && ch != '\n')
{
buff[i++] = ch;
if (i == 127)
{
str += buff;
i = 0;
}
ch = in.get();
}
if (i != 0)
{
buff[i] = '\0';
str += buff;
}
return in;
}
三.总代码
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
namespace lsh
{
class string
{
public:
/*string(const char* str) //函数体内赋值
{
size_t size = strlen(str);
_size = size;
_capacity = _size;
_str = new char[_capacity+1]; // +1 存放 \0
memcpy(_str, str, sizeof(size + 1)); //拷贝字符
}*/
string(const char* str="") // 只有初始化列表按声明顺序走
:_size(strlen(str))
, _capacity(_size)
, _str(new char[_capacity + 1])
{
memcpy(_str, str,_size+1);
}
string(const string& str) //拷贝构造
{
_str = new char[str._capacity+1];
_capacity = str._capacity;
_size = str._size;
memcpy(_str, str._str, str._size + 1);
}
~string()
{
delete[] _str;
_str = nullptr;
_size = _capacity = 0;
}
const char* c_str() const
{
return _str;
}
size_t size() const
{
return _size;
}
size_t capacity() const
{
return _capacity;
}
bool empty()const
{
return _size == 0;
}
char& operator[](size_t pos)
{
assert(pos < _size);
return _str[pos];
}
const char& operator[](size_t pos) const
{
assert(pos < _size);
return _str[pos];
}
typedef char* iterator;
typedef const char* const_iterator;
iterator begin()
{
return _str;
}
iterator begin() const
{
return _str;
}
iterator end() // 返回\0的地址
{
return _str + _size;
}
iterator end() const // 返回\0的地址
{
return _str + _size;
}
void reserve(size_t capacity)
{
if (capacity > _capacity) //不缩容
{
char* tmp = new char[capacity+1]; //多开\0
memcpy(tmp, _str, _size+1); //\0也要拷贝
_capacity = capacity;
delete[] _str;
_str = tmp;
}
}
void push_back(const char c) //尾插一个C字符
{
if (_size == _capacity)
{
reserve(_capacity==0?4:2 * _capacity); // _capacity为0的话,2*_capacity为0
}
_str[_size++] = c; //更新_size
_str[_size] = '\0'; //扩完容+'\0'
}
void append(const char* str)
{
int len = strlen(str);
if (_size + len > _capacity)
{
//至少扩容到_size+str的长度
reserve(_size + len);
}
for (size_t i = 0; i < len; i++)
{
_str[_size++] = str[i]; //更新_size
}
_str[_size] = '\0';
}
void append(string& str)
{
if (_size + str._size > _capacity)
{
//至少扩容到_size+str的长度
reserve(_size + str._size);
}
for (size_t i = 0; i < str._size; i++)
{
_str[_size++] = str[i]; //更新_size
}
_str[_size] = '\0';
}
string& operator+=(const char* str) //这里的string是namespace内的
{
append(str);
return *this;
}
string& operator+=(const char c)
{
push_back(c);
return* this;
}
bool operator> (const string& s)
{
size_t i = 0;
while (i<_size && i<s.size())
{
if (_str[i] > s[i])
return 1;
else if (_str[i] < s[i])
return 0;
else
i++;
}
if (i == _size && i != s.size())
return 0;
else if (i == _size && i == s.size())
return 0;
else
return 1;
}
bool operator< (const string& s)
{
size_t i = 0;
while (i < _size && i < s.size())
{
if (_str[i] > s[i])
return 0;
else if (_str[i] < s[i])
return 1;
else
i++;
}
if (i == _size && i != s.size())
return 1;
else if (i == _size && i == s.size())
return 0;
else
return 0;
}
bool operator>= (const string& s)
{
size_t i = 0;
while (i < _size && i < s.size())
{
if (_str[i] > s[i])
return 1;
else if (_str[i] < s[i])
return 0;
else
i++;
}
if (i == _size && i != s.size())
return 0;
else if (i == _size && i == s.size())
return 1;
else
return 1;
}
bool operator<= (const string& s)
{
size_t i = 0;
while (i < _size && i < s.size())
{
if (_str[i] > s[i])
return 0;
else if (_str[i] < s[i])
return 1;
else
i++;
}
if (i == _size && i != s.size())
return 1;
else if (i == _size && i == s.size())
return 1;
else
return 0;
}
bool operator== (const string& s)
{
if (_size == s._size)
{
size_t i= 0;
while (i < _size)
{
if (_str[i] != s[i])
{
return 0;
}
i++;
}
return 1;
}
return 0;
}
bool operator!= (const string& s)
{
if (_size == s._size)
{
size_t i = 0;
while (i < _size)
{
if (_str[i] == s[i])
{
i++;
}
else return 1;
}
return 0;
}
return 1;
}
void insert(size_t pos, const char* str)
{
assert(pos<=_size);
size_t len = strlen(str);
if (len + _size > _capacity)
{
reserve(len + _size);
}
/*memcpy(_str + pos + len, _str + pos, len);
memcpy(_str + pos,(char*)str, len);*/
/*size_t end = _size;
while (end >= pos) //如果pos为0 end最后一次变成-1,整形提升变成42e,无限循环
{
_str[end + len] = _str[end];
end--;
}*/
int end = _size;
while (end >= (int)pos) //如果pos为0 end最后一次变成-1,整形提升变成42e,无限循环
{
_str[end + len] = _str[end];
end--;
}
for (size_t i = 0; i < len; i++)
{
_str[pos++] = str[i];
}
_size += len;
_str[_size] = '\0';
}
void insert(size_t pos, size_t n,const char c)
{
assert(pos <= _size);
if (_size + n > _size)
{
reserve(_size + n);
}
int end = _size;
while (end >= (int)pos) //如果pos为0 end最后一次变成-1,整形提升变成42e,无限循环
{
_str[end + n] = _str[end];
end--;
}
for (size_t i = 0; i < n; i++)
{
_str[pos++] = c;
}
_size += n;
_str[_size] = '\0';
}
void erase(size_t pos, size_t len =npos)
{
assert(pos <= _size);
if (len == npos || pos + len >= _size)
{
_str[pos] = '\0';
_size = pos;
_str[_size] = '\0';
}
else
{
size_t end=pos+len;
while (end <= _size)
{
_str[pos++] = _str[end++];
}
_size -= len;
_str[_size] = '\0';
}
}
void swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
size_t find(const char c, size_t pos = 0) const
{
assert(pos < _size);
for (size_t i = pos; i < _size; i++)
{
if (c == _str[i])
{
return i;
}
}
return npos;
}
size_t find(const char* str, size_t pos = 0) const
{
assert(pos < _size);
const char*p=strstr(_str, str);
if(p)
{
return p-_str;
}
else
return npos;
}
string substr(size_t pos = 0, size_t len = npos) const
{
assert(pos < _size);
size_t n = len;
if (len == npos || len + pos > _size)
{
n = _size - pos;
}
string tmp;
tmp.reserve(n);
for (size_t i = pos; i < n; i++)
{
tmp += _str[i];
}
return tmp;
}
void resize(size_t n, char c = '\0')
{
if (n < _size)
{
_size = n;
_str[_size] = '\0';
}
else
{
reserve(n);
for (size_t i = _size; i < n; i++)
{
_str[i] = c;
}
_size = n;
_str[_size] = '\0';
}
}
void clear()
{
_str[0] = '\0';
_size = 0;
}
private:
size_t _size;
size_t _capacity;
char* _str;
const static int npos;
};
const int string::npos = -1;
}
ostream& operator<<(ostream& out, const lsh::string& str) // <<是全部输出,用c_str会遇到\0停止
{
for (size_t i = 0; i < str.size(); i++)
{
out << str[i];
}
out << endl;
return out;
}
istream& operator>>(istream& in, lsh::string& str) // <<是全部输出,用c_str会遇到\0停止
{
str.clear();
char ch=0;
while (ch == ' ' || ch == '\n')
{
ch = in.get();
}
char buff[128] = {0}; //用栈,尽量少扩容
ch=in.get();//cin自动跳过\n和' '
int i=0;
while (ch != ' ' && ch != '\n')
{
buff[i++] = ch;
if (i == 127)
{
str += buff;
i = 0;
}
ch = in.get();
}
if (i != 0)
{
buff[i] = '\0';
str += buff;
}
return in;
}