一、构造对象
使用string定义字符串
使用string(const string& s)拷贝构造
使用string(const string* s)拷贝构造
使用迭代器string(first, end)(在STL中所有区间都是左闭右开的)
void Teststring01()
{
string s1;
string s2("hello world");
string s3(s2);
const char* p = "hello";
string s4(p, p + 3);
cout << s2 << " " << s3 << " " << s4 << endl;
cin >> s1;
cout << s1 << endl;
}
由于迭代器都是左闭右开缘故,以至于打印出来的s4只有hel三个元素,p+3指向了第二个l但是却没有包含第二个l的位置。
二、容量
size() | length() 使用size与length都是用来获取字符串一般使用size()
capacity() 获取底层空间大小
empty() 检查字符串是否为空串
clear() 将有效元素清空,不会修改底层空间总的大小
void TestString02()
{
string s("hello world");
cout << s.size() << endl;
cout << s.length() << endl;
cout << s.capacity() << endl;
if (s.empty())
{
cout << "s is empty" << endl;
}
else
{
cout << "s is not empty" << endl;
}
s.clear();
cout << s.size() << endl;
if (s.empty())
{
cout << "s is empty" << endl;
}
else
{
cout << "s is not empty" << endl;
}
}
三、reserve()
reserve(size_t newcapacity);用来进行扩容的
定义一个字符串s ,它的起始容量就是15 当调用上图代码使其的容量扩增时,它的capacity数目是逐步增加的(发现超过一段区域才会增加到下一段区域)
1、通过reverse将string底层的空间扩大
如果newcapacity > oldcapacity;空间确实会变大
string类内部会根据一定的机制去跟随用户传入的容量去计算新的容量(通常机制为前一个容易的1.5倍)
(后一个容量大抵为前一个容量的1.5倍)
15
31
47
70
105
157
235
352
可是代码继续执行的时候缺发生了这样的问题:capacity的值不发生改变了,reserve使得字符串扩容到一定规格后,进行减少的话,它的capacity就不会跟着我们的想法继续变小了。
当到达这一步时,执行了reserve(15)之后,字符串的容量发生了改变,并且在此之后capacity不发生改变一直为15.,即只有当容量小于16才会将底层空间缩小到15.
2、为什么呢?
在vs使用的STL版本中:PJ版本
string对象内部包含了一个固定大小的数组-->char buff[16]
因为绝大多数的字符串都是小于16的,比如:人的名字、单词等
直接使用了固定大小的空间,不从堆上开辟空间可以让string类的效率更高
当元素超过16个之后,string类才需要真正从堆上开辟空间
从堆上开辟时间是有时间消耗,所以从堆上申请空间成功之后一般不会再将空间缩小。
void TestString03()
{
string s("hello");
s.reserve(20);
s.reserve(40);
s.reserve(70);
s.reserve(110);
s.reserve(80);
s.reserve(50);
s.reserve(30);
s.reserve(17);
s.reserve(16);
s.reserve(15);
s.reserve(14);
s.reserve(13);
s.reserve(5);
string ss(50, 'A');
ss.reserve(10);
cout << sizeof(string) << endl;
}
四、resize(size_t newsize, char ch = '\0');
将有效元素个数修改到newsize,如果newsize大于string对象中原有字符的个数多出的字符用ch进行填充,并且会进行扩容,然后使用ch进行填充多出来的字符
当newsize小于string对象中的有效元素个数时,将有效元素个数缩小到newsize个,
在缩小的时候不会改变容量。
void TestString04()
{
string s("hello");
s.resize(10, 'A');
s.resize(20, 'B');
s.resize(40, 'C');
s.resize(30);
s.resize(20);
s.resize(17);
s.resize(16);
s.resize(15);
s.resize(5);
}
五、元素访问
使用字符串string可以像c中访问字符数组一样使用下标访问,但是也不能越界访问。
对于利用下标访问越界有俩种访问方式对应了俩种报错提醒方式:
六、修改
operator+=:在string之后拼接:单个字符、C格式的字符串、String
append:在string之后拼接:单个字符、C格式的字符串、string对象
push_back(char ch):往string尾部插入ch
void TestString08()
{
string s("hello");
s.push_back(' ');
s += "world";
string ss("!!!");
s += ss;
s += '$';
}
append:
void TestString09()
{
string s("hello");
s.append(1, ' '); // s.push_back(' ') || s += ' ';
s.append("world"); // s += "world"
string ss("!!!");
s.append(ss); // s += ss;
s.append(5, '$');
string str("123456");
s.append(str, 1, 3); // 将str内部234拼接到s中
// 将str中第1号下标开始的3个数插入到s中
}
七、insert() 与 erase()
basic_string& insert(size_type p0, const E *s); basic_string& insert(size_type p0, const E *s, size_type n); basic_string& insert(size_type p0,const basic_string& str); basic_string& insert(size_type p0,const basic_string& str, size_type pos, size_type n); basic_string& insert(size_type p0, size_type n, E c); iterator insert(iterator it, E c); void insert(iterator it, const_iterator first, const_iterator last); void insert(iterator it, size_type n, E c);
void TestString10()
{
string s("hello");
// 在0号位置插入3个'A'
s.insert(0, 3, 'A');
// 0号位置插入字符串“world”
s.insert(0, "world");
// 7号下标插入ss字符串“BBBB”
string ss("BBBB");
s.insert(7, ss);
// 从s的开始位置 将ss的从头到尾元素均插入到s中
s.insert(s.begin(), ss.begin(), ss.end());
}
void TestString11()
{
string s("hello world");
// 删除区间[0, 6)中的元素
s.erase(0, 6);
// 删除第2号下标元素 || 从begin()位置开始偏移俩格
s.erase(s.begin() + 2);
// 从头删到尾 相当于 clear()
s.erase(s.begin(), s.end()); // s.clear();
}
八、sort() 与 reverse()
头文件algorithm
#include<algorithm>
void TestString13()
{
string s("12345678");
cout << s << endl;
reverse(s.begin(), s.end());
cout << s << endl;
sort(s.begin(), s.end());
cout << s << endl;
}