前言:
这篇文章旨在帮助读者回忆如何使用string,并提醒注意事项。它不是一篇详细的功能介绍,而是一篇润色文章。
先展示重载函数,如果该函数一笔不可带过,就先展示英文原档(附带翻译),最后展示代码实现与举例
这里先提供c++官网相关链接:cplusplus.com/reference/string/
可以直接去看英文文档,也可以看本篇文章,但是更建议去看英文原档。
那么废话少说直接开始进行挨个介绍
Member functions:
1:std::basic_string::basic_string构造函数
进行初始化,c++的官方给了很多的初始化重载函数,也完美应对了我们不同的要求,看来c++祖师爷还是很细心的。
下面举一个例子,使用每一个初始化方式
#include<string> #include<iostream> 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下一个位置的迭代器。
注意点:
If the object is an empty string, this function returns the same as basic_string::begin.
如果对象为空字符串,则此函数返回与 basic_string::begin 相同的值。
这一点也就解决了如果string为空的情况
3:rbegin与rend
reverse_iterator rbegin();
const_reverse_iterator rbegin() const;reverse_iterator rend();
const_reverse_iterator rend() const;
两个是对应的begin与end其中r为reverse逆置的意思
返回的都是字符串反向端的反向迭代器。
举例:
#include<string> #include<iostream> 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
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
const_reverse_iterator crbegin() const noexcept;
const_reverse_iterator crend() const noexcept;
Capacity
1:size
size_type size() const;
返回string的大小
这个还是很好理解的,直接展示代码的自己实现
size_t size() const
{
return _size;
}
2:length
这个函数跟size()其实没什么区别,而且用的很少,他出现的原因就是因为string是早期的c++产物,当时c++还不成熟,就造出了他,到后面也不能删除导致的。
3:max_size
size_type max_size() const;
这个就是返回string中size最大是多大
4:resize
void resize (size_type n);
void resize (size_type n, charT c);
这个函数就是修改size的值,意在修改string的大小
在函数也对应了两种特殊情况;第1种便是n的值比原来的size大,还有1种是比原来的小;
那么我们看看原档对于此的解决
If n is smaller than the current string length, the current value is shortened to its first n character, removing the characters beyond the nth.
如果 n 小于当前字符串长度,则当前值将缩短为其第一个 n 字符,从而删除第 n 个字符之外的字符。
If n is greater than the current string length, the current content is extended by inserting at the end as many characters as needed to reach a size of n. If c is specified, the new elements are initialized as copies of c, otherwise, they are value-initialized characters (null characters).
如果 n 大于当前字符串长度,则通过在末尾插入所需数量的字符来扩展当前内容,以达到 n 的大小。如果指定了 c,则新元素将初始化为 c 的副本,否则,它们是值初始化的字符(空字符)。
那么展示代码的实现:
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
size_type capacity() const;
该函数与size差不多,但这个还是是返回capacity的大小
size_type capacity() const;
{
return _capacity;
}
6:reserve
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
void clear();
该函数也是人如其名,进行了清理clear,所以函数的实现还是比较好理解的。这里不再进行多说那么这些进行代码展示
Erases the contents of the basic_string, which becomes an empty string (with a length of 0 characters).
擦除basic_string的内容,该内容将变为空字符串( 0 字符长度)。
void clear()
{
_str[0] = '\0';
_size = 0;
}
8:empty
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
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
reference at (size_type pos);
const_reference at (size_type pos) const;
at与operator[]效果完全差不多,但是有一点不同的是operator在出错时会掏出他的七匹狼给你直接报告,但是at出错时只是会警告,所以at使用的很少
3:back与front
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 <class InputIterator> basic_string& append (InputIterator first, InputIterator last); |
initializer list(7) | basic_string& append (initializer_list<charT> 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 (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 <class InputIterator> basic_string& assign (InputIterator first, InputIterator last); |
initializer list(7) | basic_string& assign (initializer_list<charT> il); |
move (8) | basic_string& assign (basic_string&& str) noexcept; |
Assign content to string
将内容分配给字符串Assigns a new value to the string, replacing its current contents.
为字符串分配一个新值,替换其当前内容。(1) string (1) 字符串
Copies str. 副本 str.
(2) substring (2) 子字符串
Copies the portion of str that begins at the character position subpos and spans sublen characters (or until the end of str, if either str is too short or if sublen is basic_string::npos).
复制从字符位置 subpos 开始并跨越 sublen 字符的 str 部分(如果任一 str 太短或 sublen 为 basic_string::npos,则复制到 str 的末尾)。(3) c-string (3) C-串
Copies the null-terminated character sequence (C-string) pointed by s.
复制以 s 为结尾的以 null 结尾的字符序列(C 字符串)。
The length is determined by calling traits_type::length(s).
长度由调用 traits_type::length(s) 确定。(4) buffer (4) 缓冲器
Copies the first n characters from the array of characters pointed by s.
从 s 指向的字符数组中复制前 n 个字符。(5) fill (5)填写
Replaces the current value by n consecutive copies of character c.
将当前值替换为字符 c 的 n 个连续副本。(6) range (6) 范围
Copies the sequence of characters in the range [first,last), in the same order.
以相同的顺序复制 范围 [first,last) 中的字符序列。(7) initializer list (7) 初始值设定项列表
Copies each of the characters in il, in the same order.
以相同的顺序复制 il 中的每个字符。(8) move (8) 移动
Acquires the contents of str.
获取 str 的内容。
str is left in an unspecified but valid state.
str 保持未指定但有效的状态。
简单举例演示
#include<string> #include<iostream> 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 <class InputIterator> iterator insert (iterator p, InputIterator first, InputIterator last); |
initializer list (8) | basic_string& insert (const_iterator p, initializer_list<charT> 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
就是代替,这个用的不是很多,就不想insert与erase那样全部展示了,就举个简单的例子吧
#include<string> #include<iostream> 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
获取 C 字符串等效值
通常可以应用输出流
代码实现
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<string> #include<iostream> 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
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;
}
那么到这里这篇文章就结束了,本篇文章不是详细介绍,而是帮助回忆!!!
看到这了就给自己点个赞把