手撕容器string(了解底层)2
·
目录
简介:
本文为上篇内容的后半部分,看本文之前最好先看前一部分内容
1.指定位置插入删除的实现
1.1指定位置插入字符串
void string::insert(size_t pos, const char* str)
{
assert(pos <= _size);
size_t len = strlen(str);
if (_size + len > _capacity)
{
reserve(std::max(_size + len, _capacity * 2));
}
// 挪动数据
/*int end = _size;
while (end >= (int)pos)
{
_str[end + len] = _str[end];
--end;
}*/
size_t end = _size + len;
while (end > pos + len - 1)//与上边的情况相比避免了无符号整型溢出的情况
{
_str[end] = _str[end - len];
--end;
}
//strncpy(_str + pos, str, len);
memcpy(_str + pos, str, len);
_size += len;
}
1.2指定位置删除指定长度字符串
void string::erase(size_t pos, size_t len)
{
assert(pos < _size);
if (len == npos || len >= _size - pos)//npos是整数的最大值
{
// 删完
_size = pos;
_str[_size] = '\0';
}
else
{
// 删部分
//strcpy(_str + pos, _str + pos + len);
memcpy(_str + pos, _str + pos + len, _size - (pos + len) + 1);
_size -= len;
}
}
1.3将字符串长度调整到指定长度
void string::resize(size_t n, char ch)
{
if (n <= _size)
{
// 删除,保留前n个
_size = n;
_str[_size] = '\0';
}
else
{
reserve(n);
for (size_t i = _size; i < n; i++)//多出来的用指定字符补齐
{
_str[i] = ch;
}
_size = n;
_str[_size] = '\0';
}
}
1.4从指定位置开始找指定字符和指定字符串
size_t string::find(char ch, size_t pos)
{
assert(pos < _size);
for (size_t i = pos; i < _size; i++)
{
if (_str[i] == ch)
return i;
}
return npos;//找不到返回-1
}

size_t string::find(const char* str, size_t pos)
{
assert(pos < _size);
const char* ptr = strstr(_str + pos, str);
if (ptr)
{
return ptr - str;
}
else
{
return npos;
}
}
2.拷贝构造,赋值操作符重载,以及子字符串拷贝
2.1拷贝构造函数
// string s2(s1);
string::string(const string& s)
{
_str = new char[s._capacity + 1];//因为_capacity不包括\0,所以加一
//strcpy(_str, s._str);
memcpy(_str, s._str, s._size + 1);//与上同理
_size = s._size;
_capacity = s._capacity;
}
2.2赋值操作符重载
当双目操作符作为成员函数重载时,第一个操作数为当前对象(this),第二个操作数通过参数传递
// s1 = s3
string& string::operator=(const string& s)
{
if (this != &s)
{
char* tmp = new char[s._capacity + 1];
//strcpy(tmp, s._str);
memcpy(tmp, s._str, s._size + 1);
delete[] _str;
_str = tmp;
_size = s._size;
_capacity = s._capacity;
}
return *this;
}
2.3子字符串拷贝
string string::substr(size_t pos, size_t len)
{
assert(pos < _size);
if (len == npos || len > _size - pos)
{
len = _size - pos;
}
string sub;
sub.reserve(len);
for (size_t i = 0; i < len; i++)
{
sub += _str[pos + i];
}
return sub;
}
3关系操作符的重载
bool string::operator==(const string& s) const
{
return strcmp(_str, s._str) == 0;
}
bool string::operator<(const string& s) const
{
return strcmp(_str, s._str) < 0;
}
bool string::operator<=(const string& s) const
{
return *this < s || *this == s;
}
bool string::operator>(const string& s) const
{
return !(*this <= s);
}
bool string::operator>=(const string& s) const
{
return !(*this > s);
}
bool string::operator!=(const string& s) const
{
return !(*this == s);
}
4.输入输出操作符重载
输入输出操作符只能被重载成全局函数,需要访问私有成员变量时可将其声明为友缘函数。
std::ostream& operator<<(std::ostream& out, const string& s)
{
for (auto ch : s)
{
out << ch;
}
return out;
}
std::istream& operator>>(std::istream& in, string& s)
{
s.clear();
char buff[256];
int i = 0;
char ch;
//in >> ch;拿不到空格
ch = in.get();//一个字符一个字符地拿
while (ch != '\n' && ch != ' ')
{
buff[i++] = ch;
if (i == 255)
{
buff[i] = '\0';
s += buff;
i = 0;
}
ch = in.get();
}
if (i > 0)
{
buff[i] = '\0';
s += buff;
}
return in;
}
std::istream& getline(std::istream& in, string& s, char delim )
{
s.clear();
char buff[256];
int i = 0;
char ch;
//in >> ch;
ch = in.get();
while (ch != delim)
{
buff[i++] = ch;
if (i == 255)
{
buff[i] = '\0';
s += buff;
i = 0;
}
ch = in.get();
}
if (i > 0)
{
buff[i] = '\0';
s += buff;
}
return in;
}
摘要:
本文是字符串类实现的后半部分,重点介绍了插入、删除、查找等核心功能的实现细节。通过指定位置插入字符串时处理容量不足和内存挪动,删除操作区分全删与部分删除的情况。查找功能支持字符和子串定位,拷贝构造与赋值操作确保深拷贝正确性。关系运算符重载基于strcmp实现字符串比较,输入输出运算符重载则通过缓冲机制高效处理流数据。整体实现了标准字符串类的关键功能。
更多推荐


所有评论(0)