前言
一、标准库中的string类
1.1 string类
- 字符串的表示字符序列的类
- 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作
单字节字符字符串的设计特性。 - string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型(关于模板的更多信
息,请参阅basic_string)。 - string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits
和allocator作为basic_string的默认参数(根于更多的模板信息请参考basic_string)。 - 注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个
类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作。
2.2 string类中的常用接口说明+模拟实现
2.2.1 string类对象的常见构造+模拟实现
函数名称 | 功能说明 |
---|
string(); | 构造一个空字符串 |
– | – |
string (const string& str); | 拷贝构造函数 |
– | – |
string (const string& str, size_t pos, size_t len = npos); | 复制从字符位置开始的str部分,并跨度len字符 |
– | – |
string (const char* s); | 用字符串构造string类对象 |
– | – |
string (const char* s, size_t n); | 构造s所指向的字符序列,赋值n个字符 |
– | – |
string (size_t n, char c); | 构造一个字符序列为n个c的类对象 |
– | – |
代码演示:
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s1;
string s4("hello world");
string s5("hello world", 7);
string s6(10, 'x');
string s2(s4);
string s3(s4, 6, 3);
cout << "s1:"<< s1.c_str() << endl;
cout << "s4:" << s4.c_str() << endl;
cout << "s5:" << s5.c_str() << endl;
cout << "s6:" << s6.c_str() << endl;
cout << "s2:" << s2.c_str() << endl;
cout << "s3:" << s3.c_str() << endl;
}
运行结果:
模拟实现
由于上面有些接口不常用,所以我就模拟实现了一部分常用的接口
namespace cxy
{
class string
{
public:
string(const char*s = "")
{
if (s==nullptr)
return;
_size = strlen(s);
_capacity = _size;
_str = new char[_capacity + 1];
strcpy(_str, s);
}
const char* c_str()
{
return _str;
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
string (const string& str) |
---|
void swap (string& str) |
namespace cxy
{
class string
{
public:
void swap(string& str)
{
::swap(_size, str._size);
::swap(_capacity, str._capacity);
::swap(_str, str._str);
}
string(const char*s = "")
{
if (s==nullptr)
return;
_size = strlen(s);
_capacity = _size;
_str = new char[_capacity + 1];
strcpy(_str, s);
}
string(const string& str)
:_str(nullptr), _size(0), _capacity(0)
{
string tmp(str._str);
swap(tmp);
}
char* c_str()
{
return _str;
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
2.2.2 string类对象的容量操作+模拟实现
代码演示:
int main()
{
string s1("hello world");
cout <<"s1.size(): " <<s1.size() << endl;
cout <<"s1.length(): "<< s1.length() << endl;
cout <<"s1.capacity(): "<<s1.capacity() << endl;
cout <<"s1:"<< s1 << endl;
cout << endl;
s1.clear();
cout <<"s1:"<< s1 << endl;
cout << "s1.size(): " << s1.size() << endl;
cout << "s1.capacity(): " << s1.capacity() << endl;
cout << endl;
s1 = "hello world";
cout << "s1:" << s1 << endl;
cout << "s1.size(): " << s1.size() << endl;
cout << "s1.capacity(): " << s1.capacity() << endl;
s1.resize(17,'x');
cout << "s1:" << s1 << endl;
cout << "s1.size(): " << s1.size() << endl;
cout << "s1.capacity(): " << s1.capacity() << endl;
s1.resize(27, 'x');
cout << "s1:" << s1 << endl;
cout << "s1.size(): " << s1.size() << endl;
cout << "s1.capacity(): " << s1.capacity() << endl;
s1.resize(5, 'x');
cout << "s1:" << s1 << endl;
cout << "s1.size(): " << s1.size() << endl;
cout << "s1.capacity(): " << s1.capacity() << endl;
cout << endl;
string s2("hello world");
s2.reserve(5);
cout << "s2:" << s2 << endl;
cout << "s2.size(): " << s2.size() << endl;
cout << "s2.capacity(): " << s2.capacity() << endl;
s2.reserve(100);
cout << "s2:" << s2 << endl;
cout << "s2.size(): " << s2.size() << endl;
cout << "s2.capacity(): " << s2.capacity() << endl;
}
运行结果:
得知:
reserve和resize的区别:reserve不会影响内容,resize会影响内容。
模拟实现
size_t size() const |
---|
返回字符串的有效长度 |
namespace cxy
{
class string
{
public:
size_t size()const
{
return _size;
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
size_t capacity() const |
---|
返回空间的大小 |
namespace cxy
{
class string
{
public:
size_t capacity()const
{
return _capacity;
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
bool empty() const |
---|
检测字符串释放为空串,是返回true,否则返回false |
namespace cxy
{
class string
{
public:
bool empty()const
{
return _str == 0;
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
void clear() |
---|
清空有效字符 ,不会改变容量 |
namespace cxy
{
class string
{
public:
void clear()
{
_size = 0;
_str[_size] = '\\0';
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
void reserve (size_t n = 0) |
---|
请求改变容量 ,此功能对字符串长度没有影响,无法改变其内容 |
- 如果 n 大于当前字符串容量,则该函数会导致容器将其容量增加到 n 字符(或更大)
- n小于当前字符串容量时,不会发生改变
namespace cxy
{
class string
{
public:
void reserve(size_t n=0)
{
if (n > _capacity)
{
char *tmp = new char[n + 1];
strncpy(tmp,_str,_size+1);
delete[]_str;
_str = tmp;
_capacity = n;
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
补充:strncpy是C语言中的函数
功能:
- 将source中的字符串复制到destination中,且复制num个字符个数,如果在没有复制完num个字符之前,找到了source的末尾,则目标填充零,直到向其编写了总共num字符。
- 如果来source中的字符有效长度大于数字,则目的地末尾不会隐含任何空字符(’\\0’)。
- 因此,在这种情况下,目的地不应被视为无效终止的 C 字符串(因此读取它将溢出,所以这种时候记得要在末尾添加’\\0’)。
void resize (size_t n, char c) |
---|
void resize (size_t n) |
将有效字符的个数该成n个,多出的空间用字符c填充 |
- 将字符串大小重新变为n字符的长度。
- 如果 n 小于当前字符串长度,则当前值将缩短为其第一个 n 字符,从而删除 n 之外的字符。
- 如果 n 大于当前字符串长度,则通过在末尾插入尽可能多的字符c以达到 n 的大小来扩展当前内容。
- 如果指定c,则新元素初始化为c的副本,否则,它们是值初始化字符(空字符)。
namespace cxy
{
class string
{
public:
void resize(size_t n,char c='\\0')
{
if (n<_size)
{
_size = n;
_str[_size] = '\\0';
}
else
{
if (n > _capacity)
{
reserve(n);
}
memset(_str + _size, c, n - _size);
_size = n;
_str[_size] = '\\0';
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
补充:memset是C语言中的函数
功能:
- 将value传到prt中,以第一个位置开始传,传num个,传完为止。
【大总结】
- size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。
- clear()只是将string中有效字符清空,不改变底层空间大小。
- resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大
- reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小。
2.2.3 string类对象的访问及遍历操作+模拟实现
代码演示:
int main()
{
string s("hello world");
cout << "operator[] :";
for (size_t i = 0; i < s.size(); i++)
cout << s[i] ;
cout << endl;
string::iterator it = s.begin();
cout << "iterator :";
while (it != s.end())
{
cout << *it ;
++it;
}
cout << endl;
cout << "范围for :";
for (auto ch : s)
{
cout << ch ;
}
cout << endl;
}
模拟实现
const char& operator[] (size_t pos) const |
---|
namespace cxy
{
class string
{
public:
const char& operator[](size_t pos)const
{
assert(pos < _size);
return _str[pos];
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
iterator begin() | iterator end() |
---|
namespace cxy
{
class string
{
public:
typedef char* iterator;
iterator begin()
{
return _str;
}
iterator end()
{
return _str+_size;
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
在这里不实现,知道怎么用就行
2.2.4 string类对象的修改操作+模拟实现
代码演示:
int main()
{
string s("hello world");
s.push_back('K');
cout << s << endl;
s.append("SSSSS");
cout << s << endl;
s += "FF";
cout << s << endl;
cout << s.find("KSS") << endl;
s.erase(11, 8);
cout << s << endl;
}
运行结果:
模拟实现:只实现了一些常用的接口
void push_back (char c) |
---|
在字符串后面插入字符c |
namespace cxy
{
class string
{
public:
void push_back(char c)
{
if (_size == _capacity)
{
reserve(_capacity * 2);
}
_str[_size] = c;
_str[_size+1] = '\\0';
_size++;
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
string& append (const char*s) |
---|
在字符串后面追加字符串s |
namespace cxy
{
class string
{
public:
string &append(const char*s)
{
size_t len = strlen(s)+_size;
if (len > _capacity)
{
reserve(len);
}
strncpy(_str + _size, s, len - _size+1);
_size = len;
return *this;
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
string& operator+= (const char* s) |
---|
在字符串后面追加字符串s |
namespace cxy
{
class string
{
public:
string& operator+=(const char*s)
{
append(s);
return *this;
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
const char* c_str() const |
---|
返回c格式的字符串 |
namespace cxy
{
class string
{
C++STL之string类的使用和实现
C++初阶:STL —— stringstring类 | 浅拷贝和深拷贝(传统写法和现代写法) | string类的模拟实现
C++初阶:STL —— stringstring类 | 浅拷贝和深拷贝(传统写法和现代写法) | string类的模拟实现
C++STL第二篇:vector类的介绍及模拟实现
C++STL第二篇:vector类的介绍及模拟实现
[C/C++]详解STL容器7--红黑树的介绍及部分模拟实现