【C++】---STL之string详解
一、STL简介
- 什么是STL?
STL(standard template libaray-标准模板库):是C++标准模版库 - STL的六大组件:
二、string类
1、string类定义
C语言中,字符串是以’\0’结尾的一些字符的集合。
但是,C++的标准库中定义了string类:
-
string是表示字符串的字符串类
-
该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
-
string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator> string;
-
不能操作多字节或者变长字符的序列。
注意:在使用string类时,必须包含#include头文件以及using namespace std;
2、string类的构造函数
最重要的是这三个:(1)无参构造(2)拷贝构造(3)字符串构造
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string>
using namespace std;
#include<iostream>
void test_string1()
{
string s0 = "hello bite";
string s1;// 1.无参的构造函数
// string s1(); 错误,无参构造不用加括号(这样写相当于一个声明了!!!)
string s2(s0);// 2.拷贝构造
string s3("hello world!"); // 3.字符串构造
// 4.部分拷贝:含有npos==-1,如果对于nops超出了范围,是有多少拷贝多少!
string s4("hello world!", 1, 4);
string s5("hello world!", 1, 100);
cout <<"s0:"<< s0 << endl;
cout << "s1:"<< s1 << endl;
cout << "s2:" << s2 << endl;
cout << "s3:" << s3 << endl;
cout << "s4:" << s4 << endl;
cout << "s5:" << s5 << endl;
}
int main()
{
test_string1();
return 0;
}
3、string类的元素访问符
- 遍历string的方法:下标+[ ]
- 这里string的[ ]调用是一个函数operator[ ],自己不写编译器也会动调用,他跟数组下标访问完全不同。
- operator[ ]的底层原理是这样的:返回的是pos位置的字符。
(是一个可读可写的!!!)
class string
{
public:
char& operator[](size_t pos)
{
return _str[pos];
}
private:
char* _str;
size_t size;
size_t capacity;
};
void test_string2()
{
string s1("Hello World!");
for (size_t i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";
}cout << endl;
}
int main()
{
//test_string1();
test_string2();
return 0;
}
- 上面的size()表示:返回某个字符串有多少个字符
- 访问string也可以用at:(at== [ ]下标)
void test_string2()
{
string s1("Hello World!");
for (size_t i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";
}cout << endl;
for (size_t i = 0; i < s1.size(); i++)
{
cout << s1.at(i) << " ";
}cout << endl;
}
int main()
{
//test_string1();
test_string2();
return 0;
}
两者的唯一区别就是他们数组越界报错的原因不一样:
下标[ ]:如果出现数组越界,报的是断言错误。
at:如果数组越界,报的是抛异常失败。
4、string类的迭代器(iterator)
string、vector支持[ ]遍历,但是list、map等容器不支持[ ]遍历,迭代器是一种可以统一使用的遍历方式。迭代器是类似于指针。因为:string、vector是有连续的储存地址!可以类似数组一样进行下标访问。
- 然后接下来要讲的迭代器则是针对于所有数据结构通用的遍历方式。
void test_string2()
{
string s1("Hello World!");
// 迭代器的行为像指针,但是它不是!
string::iterator it1 = s1.begin();
while (it1 != s1.end())
{
cout << *it1 << " ";
it1++;
}
cout << endl;
}
int main()
{
//test_string1();
test_string2();
return 0;
}
- 注意区分这里的:begin()和end()他们类似指针!
begin() :指向第一个字符!
end():指向最后一个字符的下一个位置!
即:左闭右开!
- 反向迭代器:
void test_string2()
{
string s1("Hello World!");
迭代器的行为像指针,但是它不是!
//string::iterator it1 = s1.begin();
//while (it1 != s1.end())
//{
// cout << *it1 << " ";
// it1++;
//}
//cout << endl;
string::reverse_iterator it1 = s1.rbegin();
while (it1 != s1.rend())
{
cout << *it1 << " ";
it1++;
}
cout << endl;
}
int main()
{
//test_string1();
test_string2();
return 0;
}
3. 范围for也可以用来遍历字符串(它的底层就是迭代器)
取s1的值赋值给e,e是s的拷贝,因此加引用,如果不加引用,就只能对s读,不能对s写。auto是自动推导,使用方便:
void test_string2()
{
string s1("Hello World!");
for (auto& e : s1)// 自动判断结束
{
cout << e << " ";
}
cout << endl;
}
int main()
{
//test_string1();
test_string2();
return 0;
}
- 正向遍历就多用范围for!
5、string的插入和拼接
(1)string的插入
①在字符串末尾插入:
void push_back (char c); //向字符串末尾追加一个字符
②在指定位置插入:
string& insert(size_t pos, const string& str);//插入字符串拷贝
string& insert (size_t pos, const char* s);//插入c形式的字符串
string& insert (size_t pos, const char* s, size_t n);//将字符串s的前n个字符插到pos位置
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s0("");
s0.push_back('h');//s0尾插h
cout << s0 << endl;
string s1("ell");
s0.insert(1, s1);//在下标为1的位置插入s1的拷贝
cout << s0 << endl;
s0.insert(4, "o");//在下标为4的位置插入字符串o
cout << s0 << endl;
s0.insert(0, "cplusplus",2);//在下标为0的位置插入"cplusplus"的前2个字符
cout << s0 << endl;
return 0;
}
(2)字符串的拼接
①使用append进行拼接
string& append (const string& str); //向字符串对象末尾追加字符串
string& append (const char* s);//向字符串末尾追加字符
string& append(size_t n, char c);//向字符串末尾追加n个相同字符
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s0("");
s0.append("hello");//将hello追加到s0末尾
cout << s0 << endl;
string s1 = " world";
s0.append(s1);//s0.append(s1.begin().s1.end());//将字符串s1追加到s0末尾
cout << s0 << endl;
s0.append(3, '!');//想s0末尾追加3个!
cout << s0 << endl;
//用+=追加很方便,比append更常用
s0 += '!';
s0 += " yes";
string s2 = " it is.";
s0 += s2;
cout << s0 << endl;
}
②使用全局函数operator+拼接:
string operator+ (const string& lhs, const string& rhs);//拼接lhs和rhs
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s1 = "cplusplus";
string s2 = ".com";
string s3 = s1 + s2;
cout << s3 << endl;
return 0;
}
6、string的删除
- erase:
void test_string3()
{
string s1("Hello World!");
//s1.erase(2, 2);
s1.erase(2, 100); // 如果参数2,len的常量>size,那么就全部清理完!
cout << s1 << endl;
}
int main()
{
test_string3();
return 0;
}
7、string的容量
(1)求字符串的个数
size_t size() const;//size()求字符串中有效字符的个数
size_t length() const;//length()求字符串中有效字符的个数
size( )和length( )没有区别:
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s1;
cout << s1.size() << endl;
cout << s1.length() << endl;
return 0;
}
(2)判空
bool empty() const;//判断字符串是否为空
string s1;
cout << s1.empty() << endl;
(3)容量
size_t capacity() const;//返回所分配内存的字节数
void test_string4()
{
string s1("Hello World!");
cout << s1.capacity() << endl;
cout << s1.size() << endl;
}
int main()
{
test_string4();
return 0;
}
size<capacity的原因:要给‘\0’留有空间!
(4)调整字符串的大小
只调整size大小,不填充内容!
void resize(size_t n); // n为调整后的字符串大小,
//默认插入字符'\0',32位机器一般为4的倍数,64位机器一般为8的倍数,一般按2倍去调整
void test_string4()
{
string s1("Hello World!");
s1.resize(21);
cout << s1.size() << endl;
cout << s1.capacity() << endl;
}
int main()
{
test_string4();
return 0;
}
没有走resize()之前size==12
走了resize之后:size==21且后面新增的空间全部默认为’\0’:
②调整字符串大小,并将增加的空间内容初始化成给定字符:
s1.resize(21,'x');
void test_string4()
{
string s1("Hello World!");
s1.resize(21,'x');
cout << s1.size() << endl;
cout << s1.capacity() << endl;
}
int main()
{
test_string4();
return 0;
}
(5)调整字符串的容量(reserve)
void reserve (size_t n = 0);//调整容量,缺省容量为0
void test_string5()
{
string s1("Hello World!");
cout << "szie->"<<s1.size() << endl;
cout <<"capacity->"<< s1.capacity() << endl;
s1.reserve(20);
cout << "szie->" << s1.size() << endl;
cout << "capacity->" << s1.capacity() << endl;
s1.reserve(50);
cout << "szie->" << s1.size() << endl;
cout << "capacity->" << s1.capacity() << endl;
}
int main()
{
test_string5();
return 0;
}
第二次reserve 之后的容量变成了63,是第一次reserve之后容量的2倍:
2. 查看扩容机制:
void test_string5()
{
string s1("Hello World!");
size_t cp = s1.capacity();
cout << "cp->" << cp << endl;
cout << "making a cp growing\n";
for (size_t i = 0; i < 100; i++)
{
s1.push_back('x');
if (cp != s1.capacity())// 当cp(即:原容量)!=未扩容的capacity时
{
cp = s1.capacity(); // 此时的capacity就已经扩好容了
cout << "capacity changed:" << s1.capacity() << endl;
}
}
}
int main()
{
test_string5();
return 0;
}
在不同的系统下,扩容的机制不同,比如windows中的vs和Linux的扩容机制就不同!
8、string字符串的操作(find重要)
(1)查找
size_t find(const string & str, size_t pos = 0) const;//返回在给定字符串中查找字符串str第一次出现的位置
size_t find(const char* s, size_t pos = 0) const;//返回在给定字符串中从下标为pos的位置开始查找字符串s第一次出现的位置
size_t find(const char* s, size_t pos, size_t n) const;//返回在给定字符串中从下标为pos的位置开始查找字符串s的前n个字符第一次出现的位置
size_t find(char c, size_t pos = 0) const;//返回在给定字符串中从下标为pos的位置开始查找字符c第一次出现的位置
void test_string6()
{
string s1("Hello World!");
cout << s1.find("lo", 2) << endl;// 返回在字符串s1中从下标为2的地方开始查找,字符lo第1次出现的位置。
cout << s1.find("ll") << endl;// 返回在字符串s1中,字符ll第1次出现的位置。
cout << s1.find('o') << endl;// 返回在字符串s1中,字符o第1次出现的位置。
}
int main()
{
test_string6();
return 0;
}
(2)查找子串
string substr (size_t pos = 0, size_t len = npos) const;//截取给定字符串中从第pos个位置开始的len个长度的字符
void test_string7()
{
string s1("Hello World!");
cout << s1.substr(0, 5) << endl;// 截取从下标为0的位置开始,长度len为5的字符!
}
int main()
{
test_string7();
return 0;
}
(3)反向查找
size_t rfind(const string & str, size_t pos = npos) const;//从右向左在给定字符串中查找字符串str第一次出现的位置
size_t rfind(const char* s, size_t pos = npos) const;//从右向左在给定字符串中下标为pos的位置开始查找字符串s第一次出现的位置
size_t rfind(const char* s, size_t pos, size_t n) const;//从右向左在给定字符串中从下标为pos的位置开始查找字符串s的前n个字符第一次出现的位置
size_t rfind(char c, size_t pos = npos) const;//从右向左在给定字符串中从下标为pos的位置开始查找字符c第一次出现的位置
void test_string8()
{
string s1("Hello World!");
cout << s1.rfind("He", 2) << endl;
cout << s1.rfind("el", 2) << endl;
cout << s1.rfind("lo", 2) << endl;
cout << s1.rfind('o') << endl;
}
int main()
{
test_string8();
return 0;
}
9、string字符串的比较
bool operator== (const string& lhs, const string& rhs);
bool operator== (const char* lhs, const string& rhs);
bool operator== (const string& lhs, const char* rhs);
bool operator!= (const string& lhs, const string& rhs);
bool operator!= (const char* lhs, const string& rhs);
bool operator!= (const string& lhs, const char* rhs);
bool operator< (const string& lhs, const string& rhs);
bool operator< (const char* lhs, const string& rhs);
bool operator< (const string& lhs, const char* rhs);
bool operator<= (const string& lhs, const string& rhs);
bool operator<= (const char* lhs, const string& rhs);
bool operator<= (const string& lhs, const char* rhs);
bool operator> (const string& lhs, const string& rhs);
bool operator> (const char* lhs, const string& rhs);
bool operator> (const string& lhs, const char* rhs);
bool operator>= (const string& lhs, const string& rhs);
bool operator>= (const char* lhs, const string& rhs);
bool operator>= (const string& lhs, const char* rhs);
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s1 = "cplusplus";
string s2 = ".com";
cout << (s1 == s2) << endl;
cout << (s1 == "cplusplus.com") << endl;
cout << ("cplusplus.com" == s2) << endl;
return 0;
}
好了,今天的分享就到这里了
如果对你有帮助,记得点赞👍+关注哦!
我的主页还有其他文章,欢迎学习指点。关注我,让我们一起学习,一起成长吧!