STL中的string
string在C语言中代表字符串的意思,C标准库中也有string.h的头文件里面包含了多种对字符串进行操作的函数。C++的string是一个用类模板定义的容器,是存放字符串以及对字符串操作的各种函数的封装。
对象创建与数据添加:
string只是一个类不是一个实例,我们需要在使用的时候先实例化,用string实例化了两个对象,s和s1,然后对其追加字符,我们无论追加,添加,swap交换用的都是以string里面的函数,在string外部我们是无法直接对其进行操作的,因为所有的方法和这个字符串都是被封装起来在外面只能使用看不到细节的。
string类
这个作为STL里的容器,使用场景也非常丰富,功能肯定不止上图中追加,插入的功能。string类里的功能多种多样有兴趣就可以去C++的网站查看其他类内函数。
这里就只是截取了一部分,但是里面常用的其实也不多,很多都是为了一些特别的场景设计的。
模拟实现简单版string
这里简单实现一个阉割版的string,能更深刻的认识string,这里目标是能包含平时常用的功能包括范围for
首先我们需要定义一个类
我是用了命名空间以防编译器将其与string头文件里的搞混,类里的成员变量就三个一个字符指针指向存放字符串的位置,一个大小辨识里面有多少的字符,一个容量表示现在的string容器能存放多少字符。
构造函数
我就写了两个构造函数,一个是无参构造,一个是同类构造就是复制构造。存放字符串的空间用new开辟由string类来管理。这里为了与C语言兼容即与C的字符串一样是以'\0'作结尾标志,需要要末尾手动加上这个符号。
析构函数
空间是动态开辟的自然需要释放,当对象的生命周期完结自动调用析构函数,只需要再析构函数中释放掉就好,其他的其实不写也行因为生命周期结束就会被操作系统自动释放,除非显式调用析构函数。
添加元素
这里四个函数来调加字符,看似多其实就是两个功能一个是添加一个字符一个是添加字符串,里面参数加了const修饰是因为传参可能会有(很多情况下)都传的是"abcdefg"这样的,这个是一个常量所以参数也加一个常量修饰符。
+=重载和另外两个函数功能是一样的所以是可以进行复用,只是多了一种使用方式而已。
这是随机位置插入函数,里面用了iterator就等价于char*,这是一个迭代器,string的迭代器非常简单跟指针一样就可以了。
resrve是一个扩容函数,当我们需要添加的字符加上原本的字符数比容量大需要进程扩容,这样动态调整大小可以使空间的利用效率提高。
new函数不同于malloc不能使用realloc来进行内存大小的调整,所以我们需要另外开辟一段空间将数据迁徙过去再释放掉旧空间。然后在新空间结尾加上字符串结束标志。
删除元素
尾删非常方便,并不需要直接删除,只需要将外部能访问的位置向前挪动一个字节就可以,这里就表示有效数据个数的size减一,并设置新的字符串结束标志位就可以。
第二个函数是在指定位置开始删除指定个数的数据,这里有两种情况,一种是指定删除的元素个数比字符数组的长度长,这种就相当于是将指定位置之后的所有数据删除,就直接将指定位置标志位字符串的最后一个字符,后面加上字符串结束符,更新有效数据个数就可。
第二种是删除数据少于指定位置后的数据个数,这时候就最方便就是直接覆盖,从后面不用删除的数据的第一个开始覆盖到指定位置后的第一个位置,一直到'\0'完成覆盖,更新有效数据个数完成删除。
查找
根据指定字符查找第一次出现的位置,这里写了两个函数分别是查找字符和字符串的,这两个函数多与insert和erase函数搭配使用,查找的返回值可以直接当作增加和删除的参数。查找字符串的第二个参数是指定开始位置,返回查找的字符在字符串的第几个。指针相减就等于两指针间相距多少个元素。
重载运算符
字符串的对比使用strcmp进行对比,里面大部分都是进行复用,只需要实现大于,小于和等于就可以了。
随机访问:
在C语言中指针可以使用数组的方式进行随机访问,这里不是单纯的指针所以需要对【】进行运算符重载完成随机访问的功能
这里返回的是一个引用,进行随机访问后的数据是可以修改,若是const对象则需要const函数所以重载了两份
迭代器
string的迭代器很简单因为指针就能完成
完成代码
cpp
#pragma once
#include<assert.h>
#include<iostream>
#include <string.h>
#include<stdbool.h>
namespace ljjstring
{
class string
{
public:
typedef char* iterator;
string()
{
_str = new char[1];
_str[0] = '\0';
_size = 0;
_capacity = 0;
}
string(const string& s)
{
char* tmp = new char[s._capacity + 1];
memcpy(tmp, s._str, s._size);
_str = tmp;
_capacity = s._capacity;
_size = s._size;
}
void resrve(size_t n)
{
if (n > _capacity)
{
char* tmp = new char[n+1];
_capacity = n;
memcpy(tmp, _str, _size);
delete[] _str;
_str = tmp;
}
_str[_size] = '\0';
}
void push_back(const char a)
{
if (_size >= _capacity)
{
resrve(_capacity == 0 ? 4:_capacity*2);
}
_str[_size] = a;
++_size;
_str[_size] = '\0';
}
void pop_back()
{
assert(_size != 0);
--_size;
_str[_size] = '\0';
}
size_t getsize()
{
return _size;
}
size_t getcapacity()
{
return _capacity;
}
string& operator+=(char c)
{
push_back(c);
return *this;
}
string& operator+=(const char* str)
{
while (*str != '\0')
{
if (_size + 1 > _capacity)
{
resrve(_capacity == 0 ? 4 : _capacity * 2);
}
_str[_size] = *str;
++str;
++_size;
}
_str[_size] = '\0';
return *this;
}
void append(const char* str)
{
*this += str;
}
void swap(string& s)
{
char* tmp = s._str;
s._str = _str;
_str = tmp;
size_t tmp1 = s._capacity;
s._capacity = _capacity;
_capacity = tmp1;
tmp1 = s._size;
s._size = _size;
_size = tmp1;
}
iterator begin()
{
return _str;
}
iterator end()
{
return _str + _size;
}
string& operator=(string s)
{
swap(s);
return *this;
}
bool operator==(const string & s)
{
int i=strcmp(_str, s._str);
if (i == 0)
return true;
else
return false;
}
bool operator !=(const string& s)
{
return !(*this == s);
}
bool operator>(const string& s)
{
int i = strcmp(_str, s._str);
if (i > 0)
return true;
else
return false;
}
bool operator>=(const string& s)
{
return *this > s || *this == s;
}
bool operator<(const string& s)
{
return !(*this >= s);
}
bool operator<=(const string& s)
{
return !(*this > s);
}
char& operator[](size_t n)
{
return _str[n];
}
const char& operator[](size_t n)const
{
return _str[n];
}
size_t find(char c)const
{
for (int i = 0; i < _size; i++)
{
if (_str[i] == c)
return i;
}
return -1;
}
size_t findstr(const char* str, size_t pos = 0)const
{
char* tmp=strstr(_str + pos, str);
return tmp - _str;
}
string& insert(size_t pos, const char c)
{
assert(pos <= _size);
if (_size >= _capacity)
{
resrve(_capacity == 0 ? 4 : _capacity * 2);
}
iterator tail = end();
while (tail >= _str + pos)
{
*(tail+1) = *tail;
--tail;
}
_str[pos] = c;
++_size;
return *this;
}
string& insert(size_t pos, const char* str)
{
assert(pos <= _size);
int i=strlen(str);
if (_size + i > _capacity)
{
resrve(_size + i);
}
iterator tail = end();
while (tail >= _str + pos)
{
*(tail + i) = *tail;
--tail;
}
for (int k = pos; k < pos + i; ++k)
{
_str[k] = *str;
++str;
}
_size = _size + i;
return *this;
}
string erase(size_t pos, size_t len)
{
if (pos + len >= _size)
{
_size = pos;
_str[_size] = '\0';
}
else
{
while(_str[pos]!='\0')
{
_str[pos] = _str[pos + len];
++pos;
}
_str[pos] = '\0';
_size = _size - len;
}
return *this;
}
~string()
{
delete[] _str;
_capacity = _size = 0;
}
private:
char* _str=nullptr;
size_t _size=0;
size_t _capacity=0;
};
}