前言:
这篇文章旨在帮助读者回忆如何使用string,并提醒注意事项。它不是一篇详细的功能介绍,而是一篇润色文章。
先展示重载函数,如果该函数一笔不可带过,就先展示英文原档(附带翻译),最后展示代码实现与举例
这里先提供c++官网相关链接:cplusplus.com/reference/string/
可以直接去看英文文档,也可以看本篇文章,但是更建议去看英文原档。
那么废话少说直接开始进行挨个介绍
Member functions:
1:std::basic_string::basic_string构造函数
进行初始化,c++的官方给了很多的初始化重载函数,也完美应对了我们不同的要求,看来c++祖师爷还是很细心的。
include
include
using namespace std;
int main()
{
string s0("Initial string");
// constructors used in the same order as described above:
string s1;
string s2(s0);
string s3(s0, 8, 3);
string s4("A character sequence", 6);
string s5("Another character sequence");
string s6(10, 'x');
string s7a(10, 42);
string s7b(s0.begin(), s0.begin() + 7);
cout << "s1: " << s1 << "\ns2: " << s2 << "\ns3: " << s3;
cout << "\ns4: " << s4 << "\ns5: " << s5 << "\ns6: " << s6;
cout << "\ns7a: " << s7a << "\ns7b: " << s7b << '\n';
return 0;
}
2:std::basic_string::~basic_string析构函数
析构函数官方没有给详细解释,应该走的是默认析构
那么这里展示我写的析构函数:
class string
{
public:
~string()
{
delete[]_str;
_str = nullptr;
_size = _capacity = 0;
}
private:
char* _str;
size_t _size;
size_t _capacity;
const static size_t npos = -1;//可以先忽略
};
3:std::basic_string::operator=运算符=
官方给出了三个重载
第一个就是将string类型赋值给string类型
第二个是将字符串赋值给string类型
第三个是单个字符赋值给string类型
需要注意的是自己实现的时候要进行深拷贝,而不是浅拷贝
string& operator= (const string& str)
{
if (this != &str)
{
char* tmp= new char[str._capacity + 1];
strcpy(tmp, str._str);
delete[] _str;
_str = tmp;
_size = str._size;
_capacity = str._capacity;
}
}
也可以借助swap函数进行优化:
string& operator=(string tmp)
{
swap(tmp);
return *this;
}
Iterators:
1:begin
iterator begin();
const_iterator begin() const;
官方解释就是Returns an iterator pointing to the first character of the string.
也就是返回一个指向第一个字符的string迭代器
反之对应的就是end,最后一个
2:end
iterator end();
const_iterator end() const;
需要注意的是返回的是最后一个元素的下一个,不是最后一个,
就比如说如果string里面存的是 abcdef 那么end返回的是指向f下一个位置的迭代器。
begin与end都说完了,那么结合两者进行实现迭代器遍历:
include
include
using namespace std;
int main()
{
string t("abcdef");
string::iterator it = t.begin();
while (it != t.end())
{
cout << *it << " ";
it++;
}
cout << endl;
return 0;
}
运行结果:
3:rbegin与rend
reverse_iterator rbegin();
const_reverse_iterator rbegin() const;
reverse_iterator rend();
const_reverse_iterator rend() const;
两个是对应的begin与end其中r为reverse逆置的意思
返回的都是字符串反向端的反向迭代器。
include
include
using namespace std;
int main()
{
string str("now step live...");
string::reverse_iterator it = str.rbegin();
while (it != str.rend())
{
cout << *it;
++it;
}
cout << endl;
return 0;
}
4: cbegin与cend返回到begin或end
const_iterator cbegin() const noexcept;
const_iterator cend() const noexcept;
分别是Return const_iterator to begin 回到const_iterator开始
Return const_iterator to end 返回const_iterator到结束
5:同样有crbegin与crend返回到cbegin或cend
const_reverse_iterator crbegin() const noexcept;
const_reverse_iterator crend() const noexcept;
Capacity
1:size求string对象的大小
size_type size() const;
返回string的大小
这个还是很好理解的,直接展示代码的自己实现
size_t size() const
{
return _size;
}
2:length求string对象的大小
这个函数跟size()其实没什么区别,而且用的很少,他出现的原因就是因为string是早期的c++产物,当时c++还不成熟,就造出了他,到后面也不能删除导致的。
3:max_size求string对象最大可以存贮多少字符
size_type max_size() const;
这个就是返回string中size最大是多大
4:resize 修改string的size大小
void resize (size_type n);
void resize (size_type n, charT c);
这个函数就是修改size的值,意在修改string的大小
在函数也对应了两种特殊情况;第1种便是n的值比原来的size大,还有1种是比原来的小;
那么我们看看原档对于此的解决
那么展示代码的实现:
void resize(size_t n, char ch = '\0')
{
if (n > _size)
{
reserve(n);//修改capacity大小为n后面回介绍
for (size_t i = _size; i < n; i++)
{
_str[i] = ch;
}
_str[n] = '\0';
_size = n;
}
else
{
_str[n] = '\0';
_size = n;
}
}
5:capacity求string对象的容器大小
size_type capacity() const;
该函数与size差不多,但这个还是是返回capacity的大小
size_type capacity() const;
{
return _capacity;
}
6:reserve调整string对象的capacity大小
void reserve (size_type n = 0);
该函数是在修改capacity的大小,但是它只能放大不可以缩小。主要是因为如果缩小的话,代价太过于大,而且会产生很多不必要的麻烦。所以该函数只支持放大容量不可以缩小。
代码实现也有很多小细节:主要是末尾的'\0';
void reserve(size_t n = 0)
{
if (n > _capacity)
{
char* tmp = new char[n + 1];//第n+1个位置存的是'/0'
strcpy(tmp, _str);
delete[] _str;
_str = tmp;
_capacity = n;
}
}
7:clear清空string对象存储内容
void clear();
该函数也是人如其名,进行了清理clear,所以函数的实现还是比较好理解的。这里不再进行多说那么这些进行代码展示
void clear()
{
_str[0] = '\0';
_size = 0;
}
8:empty检测string对象是否为空
bool empty() const;
Returns whether the basic_string is empty (i.e. whether its length is 0).
这句话的详细意思就是如果该对象为空就返回1(true)如果对象不为空就返回零(false);
bool empty() const
{
return _size == 0;
}
9:shrink_to_fit调整capacity的啊小使其与size相等
void shrink_to_fit();
这个函数官方的介绍还有比较少的,但是实际上实现起来还是比较麻烦的。
它的作用主要是修改修改capacity大小,使其正好达到满的效果,也就是第capacity的位置就为第size的值。
其实该函数的实现不单单是调用了reserve
因为如果原本的capacity很大很大,但是我们又删了很多,那么这时候在shrink_to_fit,就会很浪费空间,原码是这样实现的,会先拷贝,后修改,不是单单的reserve
最后展示一下官方举例
Element access: 元素访问
1: operator[](跟数组一样进行下标随机访问)
reference operator[] (size_type pos);
const_reference operator[] (size_type pos) const;
实现起来还是比较简单的这里就不在说了。
char& operator[] (size_t pos)
{
assert(pos < _size);
return _str[pos];
}
const char& operator[] (size_t pos) const
{
assert(pos < _size);
return _str[pos];
}
2:at(跟operator差不多)
reference at (size_type pos);
const_reference at (size_type pos) const;
at与operator[]效果完全差不多,但是有一点不同的是operator在出错时会掏出他的七匹狼给你直接报告,但是at出错时只是会警告,所以at使用的很少
3:back与front (返回string对象的尾或首字符)
charT& back();const charT& back() const;
charT& front();const charT& front() const;
返回第一个与最后一个
Modifiers: 修饰 符
1:operator+= (实现+=)
string (1)
basic_string& operator+= (const basic_string& str);
c-string (2)
basic_string& operator+= (const charT* s);
character (3)
basic_string& operator+= (charT c);
这个重载运算符那就不需要多的介绍了吧,我们已经很详细了,就是+=
string& operator+=(const char str)
{
append(str);
return this;
}
string& operator+=(char ch)
{
push_back(ch);
return *this;
}
2:append (附加别的对象)
string (1)
basic_string& append (const basic_string& str);
substring (2)
basic_string& append (const basic_string& str, size_type subpos, size_type sublen);
c-string (3)
basic_string& append (const charT s);
buffer (4)
basic_string& append (const charT s, size_type n);
fill (5)
basic_string& append (size_type n, charT c);
range (6)
template basic_string& append (InputIterator first, InputIterator last);
initializer list(7)
basic_string& append (initializer_list il);
可以看到C++祖师爷写了很多它的重载,也完美了应对了我们的所有要求。而且这还是C++11如果C++14的话那么就会更多.那么这里就介绍几个我们经常用到的。
函数的作用
向后添加想要对象,俗话说时延长
代码实现 :
string& append(size_t n, char c)
{
if (_size + n > _capacity)
{
reserve(_size + n);
}
size_t begin = _size;
_size += n;
for (size_t i = begin; i < _size; i++)
{
_str[i] = c;
}
return this;
}
void append(const char str)
{
size_t len = strlen(str);
if (_size + len > _capacity)
{
reserve(_size + len);
}
strcpy(_str + _size, str);
_size += len;
}
string& append(const string& str)
{
append(str._str);
return *this;
}
3:push_back与pop_back (后添加与后删)
void push_back (charT c);
void pop_back();
向后添加,与后删,这个就没有好多说的。
4:assign (将string对象的元素全部转换到别的对象内)
string (1)
basic_string& assign (const basic_string& str);
substring (2)
basic_string& assign (const basic_string& str, size_type subpos, size_type sublen);
c-string (3)
basic_string& assign (const charT s);
buffer (4)
basic_string& assign (const charT s, size_type n);
fill (5)
basic_string& assign (size_type n, charT c);
range (6)
template basic_string& assign (InputIterator first, InputIterator last);
initializer list(7)
basic_string& assign (initializer_list il);
move (8)
basic_string& assign (basic_string&& str) noexcept;
Assign content to string
将内容分配给字符串
include
include
using namespace std;
int main()
{
string str("now step live...");
string s;
s.assign(str);
auto it = s.begin();
while (it != s.end())
{
cout << *it;
++it;
}
cout << endl;
return 0;
}
5:insert (根据小标随机在其前面插入元素)
string (1)
basic_string& insert (size_type pos, const basic_string& str);
substring (2)
basic_string& insert (size_type pos, const basic_string& str, size_type subpos, size_type sublen);
c-string (3)
basic_string& insert (size_type pos, const charT s);
buffer (4)
basic_string& insert (size_type pos, const charT s, size_type n);
fill (5)
basic_string& insert (size_type pos, size_type n, charT c); iterator insert (const_iterator p, size_type n, charT c);
single character (6)
iterator insert (const_iterator p, charT c);
range (7)
template iterator insert (iterator p, InputIterator first, InputIterator last);
initializer list (8)
basic_string& insert (const_iterator p, initializer_list il);
同样c++给了很多重载,insert就是在pos的前面插入
代码实现:
string& insert(size_t pos, char ch)
{
assert(pos < _size);
if (_size == _capacity)
{
reserve(_capacity == 0 ? 4 : _capacity 2);
}
size_t end = _size + 1;
while (end > pos)
{
_str[end] = _str[end - 1];
--end;
}
_str[pos] = ch;
_size++;
return this;
}
string& insert(size_t pos, const char str)
{
assert(pos < _size);
size_t len = strlen(str);
if (_size + len > _capacity)
{
reserve(_size + len);
}
size_t end1 = _size + 1;
size_t end2 = _size + len + 1;
while (end1 > pos)
{
_str[end2 - 1] = _str[end1 - 1];
end2--;
end1--;
}
_str[_size + len] = '\0';
strncpy(_str + pos, str, len);
_size+=len;
return this;
}
6:erase (根据下标进行删除)
sequence (1)
basic_string& erase (size_type pos = 0, size_type len = npos);
character (2)
iterator erase (const_iterator p);
range (3)
iterator erase (const_iterator first, const_iterator last);
需要注意的是这里的len是删除的个数,而npos是-1;
返回值就是删除后指向的位置(为了使其迭代器不失效)
7:replace (根据下标随机替换n个对应的元素)
就是代替,这个用的不是很多,就不想insert与erase那样全部展示了,就举个简单的例子吧
include
include
using namespace std;
int main()
{
string str("now step live...");
string s1("pqpq2");
str.replace(2, 2, s1);//把str从第二个开始把两个字符,替换为s1,
auto it = str.begin();
while (it != str.end())
{
cout << *it;
++it;
}
cout << endl;
return 0;
}
通常可以与find一同使用,统一替换某个特殊字符转化为想要的结果。
8:c_str (将string转化为char*来打印)
获取 C 字符串等效值
通常可以应用输出流
简单的来说就是将string转化为char*来打印
int main()
{
string b("abcd");
cout << b.c_str();
return 0;
}
代码实现
const char* c_str() const
{
return _str;
}
9:copy (复制拷贝)
这个就是复制拷贝,很好理解
同样第一个参数就是要拷贝的对象,第二个是要拷贝的个数,第三个参数就是被拷贝的对象第一个拷贝的位置。
举例:
10:find (查找特殊的元素)
string (1)
size_type find (const basic_string& str, size_type pos = 0) const noexcept;
c-string (2)
size_type find (const charT s, size_type pos = 0) const;
buffer (3)
size_type find (const charT s, size_type pos, size_type n) const;
character (4)
size_type find (charT c, size_type pos = 0) const noexcept;
size_t find(char ch, size_t pos = 0)
{
for (size_t i = pos; i < _size; i++)
{
if (_str[i] == ch)
{
return i;
}
}
return npos;
}
include
include
using namespace std;
void test()
{
string s3("https://legacy.cplusplus.com/reference/string/string/rfind/");
// 协议
// 域名
// 资源名
string sub1, sub2, sub3;
size_t i1 = s3.find(':');
if (i1 != -1)
sub1 = s3.substr(0, i1);//可以理解为赋值从第0到第i1个
else
cout << "没有找到i1" << endl;
size_t i2 = s3.find('/', i1 + 3);
if (i2 != -1)
sub2 = s3.substr(i1 + 3, i2 - (i1 + 3));
else
cout << "没有找到i2" << endl;
sub3 = s3.substr(i2 + 1);
cout << sub1 << endl;
cout << sub2 << endl;
cout << sub3 << endl;
}
int main()
{
test();
return 0;
}
11:substr (按string对象的指定部分生成子string对象)
asic_string substr (size_type pos = 0, size_type len = npos) const;
该函数就是生成其子字符串
代码实现 :
string substr(size_t pos, size_t len = npos)
{
string s;
size_t end = pos + len;
if (len == npos || pos + len >= _size) // 有多少取多少
{
len = _size - pos;
end = _size;
}
s.reserve(len);
for (size_t i = pos; i < end; i++)
{
s += _str[i];
}
return s;
}
那么到这里这篇文章就结束了,本篇文章不是详细介绍,而是帮助回忆!!!
看到这了就给自己点个赞把