String类深拷贝写法的增删查改

来源:互联网 发布:银河麒麟linux下载 编辑:程序博客网 时间:2024/04/27 19:22

String的深拷贝写法

之所以抛弃char*的字符串而选用C++标准程序库中的string类,是因为他和前者比较起来,不必担心内存是否足够、字符串长度等等,而且作为一个泛型类出现,他集成的操作函数足以完成我们大多数情况下(甚至是100%)的需要。我们可以用 = 进行赋值操作,== 进行比较,+ 做串联(是不是很简单?)。我们尽可以把它看成是C++的基本数据类型。 
C++中对于strinig的定义为:typedef basic_string(char) string; 也就是说C++中的string类是一个泛型类,由模板而实例化的一个标准类,本质上不是一个标准数据类型。

详情请参考:http://citycowboy.blog.sohu.com/50058804.html

模拟String的增删查改

这里采用深拷贝来为String开辟所需的空间(想要了解深拷贝参考上一篇博客)。

class String
{
public:
String(const char *str)
{//利用深拷贝来开空间同时对字符串大小和空间大小进行初始化
_size = strlen(str);
_capacity = _size;
_str = new char[_capacity + 1];//多开辟一块用来存放'\0'
strcpy(_str, str);
}
String(const String& str)
{
String tmp(str._str);
Swap(tmp);//利用交换拿到需要的数据同时析构不需要的内存
}
void Swap(String& s)//这个函数很有必要存在,因为调用一次交换三个私有成员
{
swap(_str, s._str);
swap(_size, s._size);
swap(_capacity, s._capacity);
}
~String()
{
delete[] _str;
_str = NULL;
}
String& operator=(const String& str)
{
if (this != &str)
{
String tmp(str._str);// 与str的空间一样
Swap(tmp);//交换后tmp出局部域后释放
}
return *this;
}
//String& operator=(const String str)//更简洁的资本主义写法
//{
// Swap(str);
// return *this;
//}

char& operator[](size_t pos)//1不给const可读可写,2给const只读
{
assert(pos < _size);//这是一种风格,这里也可以用if语句判断
return _str[pos];
}

bool operator<(const String& s) const
{
if (s._str != NULL)
{
size_t i = 0;
while (_str[i] == s._str[i])
{
i++;
}
if (_str[i]>=s._str[i])
{
return false;
}
else
{
return true;
}
}
}
bool operator<=(const String& s) const
{
return !(*this > s);
}
bool operator>(const String& s) const
{
if (s._str != NULL)
{
size_t i = 0;
while (_str[i] == s._str[i])
{
i++;
}
if (_str[i] <= s._str[i])
{
return false;
}
else
{
return true;
}
}
}
bool operator>=(const String& s) const
{
return !(*this < s);
}
bool operator==(const String& s) const
{
return (!(*this < s) && !(*this > s));
}
bool operator!=(const String& s)const
{
return !(*this == s);
}
void Expand(size_t n)
{
if (n > _capacity)
{
_str = (char*)realloc(_str, n + 1);//
assert(_str);
_capacity = n;//增容成功把容量改为n
}
}

PushBack函数插入单个字符需要检查字符串大小和容量,一般情况下是小于容量,如果一旦等于容量则需要增容,要不然’\0’没地方存储。

    void PushBack(char ch)
{
if (_size == _capacity)
{
Expand(_capacity * 2);
}
_str[_size] = ch;
_size++;
_str[_size] = '\0';
}

PushBack函数插入一个字符串也需要检查大小和容量,一般来说插入一个字符串只需增容到源字符串的长度加上目标字符串长度。然后在源字符串的’\0’处开始将目标字符串拷入。

    void PushBack(char *s)
{
size_t len = strlen(s);
if (len + _size > _capacity)
{
Expand(len + _size);
}
strcpy(_str + _size, s);
_size += len;
}
void PopBack()
{
assert(_size < 0);
--_size;
_str[_size] = '\0';
}
void Insert(size_t pos, char ch)//需要开的空间和尾插的思路一样
{
if (_size == _capacity)
{
Expand(2 * _capacity);
}
int end = _size - 1;
while (end >= (int)pos) //1 不同类型比较存在隐式转换,
{
_str[end + 1] = _str[end];
end--;
}
_str[pos] = ch;
++_size;
_str[_size] = '\0';
}

在一个位置插入一个字符串,其增容思路和尾插字符串思路一致,这里需要注意的问题是pos为unsigned int型,再与int型比较时可能会出错,存在隐式转换的问题(两个不同类型比较时int类型会像unsigned int型转换)。在比较时需要将unsigned int型强转为int型(注意是在比较时强转)。

    void Insert(size_t pos, char* s)
{
size_t len = strlen(s);
if (_size + len > _capacity)
{
Expand(_size + len);
}
int end = (int)_size - 1;
while (end >= (int)pos)
{
_str[end + len] = _str[end];
end--;
}
while (*s)
{
_str[pos++] = *s++;
}
_str[_size + len] = '\0';//不能再加1,加1就越界
_size += len;
}

在pos位置删除count个字符时需要分析pos以后有几个字符与count比较,如果count大于它则把pos以后的字符全删了,如果count小于它则安安静静的把从pos+count起以后的字符拷到pos后面即完成任务。

    void Erase(size_t pos, size_t count)
{
if (pos + count >= _size - 1)
{
_str[pos] = '\0';
_size = pos;
}
else
{
strcpy(_str + pos, _str + pos + count);
_size -= count;
}
}
int Find(char ch)const//模拟C语言的strch函数
{
size_t i = 0;
for (; i < _size; i++)
{
if (_str[i] == ch)
{
return i;
}
}
return -1;
}
int Find(char *s)const//模拟C语言的strstr函数
{
assert(s);
size_t sublen = strlen(s);
int srcindex = 0;
int subindex = 0;
while (srcindex <= _size - sublen)
{
int tmpindex = srcindex;
while (_str[tmpindex] == s[subindex])
{
tmpindex++;
subindex++;
if (subindex == sublen)
return srcindex + 1;
}
subindex = 0;
srcindex++;
}
return -1;
}
private:
char *_str;
size_t _size; //字符个数
size_t _capacity; //容量空间
};

上述所有黑色部分为一个整体,是一个类,有些函数需要解释的部分在黑色部分外

原创粉丝点击