目录
size,length,max_size,capacity,clear基本用法
[reserve 提前开空间,避免扩容的操作](#reserve 提前开空间,避免扩容的操作)
string
为什么学习string的类
● C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。
● 在OJ中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本都使用string类,很少有人去使用C库中的字符串操作函数
● string是一个管理字符数组的类
string类的常用接口
string****类对象的常见构造
string::string - C++ Reference

int main()
{
string s1;
string s2("1111122222");
string s3("111111111111", 3); //前三个拷贝
string s4(100, 'x'); //拷贝100个x初始化
string s5(s2, 4, 3); //拷贝第四个字符起后三个字符
string s6(s2, 4); //拷贝第四个字符后所以的字符,直到结束
cout << s1 << endl;
cout << s2 << endl;
cout << s3 << endl;
cout << s4 << endl;
cout << s5 << endl;
cout << s6 << endl;
//s2.operator[](0) = 'x';
s2[0] = 'x'; //修改第零个位置的字符为x
s2[5] = 'x'; //修改第五个位置的字符为x
cout << s2 << endl;
//让s2里的所以字符++
for (size_t i = 0; i < s2.size(); i++)
{
s2[i]++;
}
cout << s2 << endl;
return 0;
}
string****类对象的访问及遍历操作

operator[]
结构
class string
{
public:
char& operator[](size_t pos)
{
assert(pos < _size);
}
private:
char* _str;
size_t _size;
size_t _capacity;
};
使用operator[]进行数组元素的遍历操作
int main()
{
//operator[]可以访问数组的第pos位置的元素,越界就会直接报错的
string s1("hello world");
for (size_t i = 0; i < s1.size(); i++)
{
cout << s1[i];//直接访问第i个位置的字符
}
return 0;
}
迭代器
通过迭代器进行遍历的实现操作,迭代器可以理解为像指针一样的东西。
int main()
{
string s1("hello world");
//string::iterator it1 = s1.begin();//用这个类型定义一个对象
//我们这里的话begin访问的是h这个字符,end指向的是\0
//这里将begin给到了it1
it1 = s1.begin();
while (it1 != s1.end())//end是最后一个数据的下一个位置
{
//下面的用法非常像指针,但是不是指针
cout << *it1 << " ";
++it1;
}
return 0;
}
//这个s1是一个类对象,然后我们利用这个string类里面的运算符

日常的通过下标[] 访问很方便,但是这个不是通用的访问方式,这个只适合string和vector结构,不适合后面的结构,string和vector结构底层是连续的空间,才回去重载operator[]。
下标+[]不是通用的方式,但是迭代器是所有容器通用的方式。
列表的遍历
int main()
{
list <int> lt;//创建一个模版对象lt
//然后进行数据的插入操作
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
//列表
list <int>::iterator it =lt.begin();
while (it != lt.end())
{
cout << *it << " ";
++it ;
}
return 0;
}
范围for
范围for进行遍历
// 范围for C++11 语法糖
// 适用于容器遍历和数组遍历
// 自动取容器的数据赋值给左边的对象
// 自动++,自动判断结束
// 原理:范围for底层是迭代器
//for (char ch : s1)
//auto可以代替类型
for (auto ch : s1)
{
cout << ch << " ";
}
cout << endl;
// 修改
for (auto& ch : s1)
{
ch++;
}
for (auto ch : s1)
{
cout << ch << " ";
}
cout << endl;
for (auto e : It)
{
cout << e << " ";
}
cout << endl;
String而言有三种遍历方式:下标+[],迭代器,范围for。
范围for用于容器遍历和数组遍历。
因为迭代器底层根指针相似,所以范围for也可以遍历数组。
auto
int i = 1;
int y = i;
//自动推导类型
auto z = y; //int
auto x = 1.1; //double
auto n = &i; //int*
int& r1 = i;
auto r2 = r1; //int
auto& r3 = r1; //int&
//list<int>::iterator it = It.begin();
auto it = It.begin();
while (it != It.end())
{
cout << *it << " ";
++it;
}
cout << endl;
//auto语法糖
// 简化代码,替代写起来长的类型
std::map<std::string, std::string> dict;
//std::map<std::string, std::string>::iterator dit = dict.begin();
auto dit = dict.begin();
auto真正的价值是为了方便,简化代码,替换长类型,写起来长的类型。
auto当前是不能作为形参的,C++20开始支持auto作参数,auto可以支持作为返回值的,谨慎使用。
// C++20开始支持
void func1(auto x);
auto func3()
{
auto y = func4();
return y;
}
auto func2()
{
auto x = func3();
//...
return x;
}
整理代码
#include<iostream>
#include<string>
#include<list>
#include<map>
using namespace std;
//int main()
//{
// string s1("hello,word");
//
// //下标[]+
// for (size_t i = 0; i < s1.size(); i++)
// {
// s1[i]++;
// }
//
// for (size_t i = 0; i < s1.size(); i++)
// {
// cout<<s1[i]<<" ";
// }
// cout << endl;
//
// //迭代器
// string::iterator it1 = s1.begin();
// while (it1 != s1.end())
// {
// (*it1)--;
// ++it1;
// }
// cout << endl;
//
// it1 = s1.begin();
// while (it1 != s1.end())
// {
// cout << *it1 << " ";
// ++it1;
// }
// cout << endl;
//
// list<int> It;
// It.push_back(1);
// It.push_back(2);
// It.push_back(3);
// It.push_back(4);
//
// //list<int>::iterator it = It.begin();
// auto it = It.begin();
// while (it != It.end())
// {
// cout << *it << " ";
// ++it;
// }
// cout << endl;
//
//
// //auto语法糖
// // 简化代码,替代写起来长的类型
// std::map<std::string, std::string> dict;
// //std::map<std::string, std::string>::iterator dit = dict.begin();
// auto dit = dict.begin();
//
// // 范围for C++11 语法糖
// // 适用于容器遍历和数组遍历
// // 自动取容器的数据赋值给左边的对象
// // 自动++,自动判断结束
// // 原理:范围for底层是迭代器
// //for (char ch : s1)
// //auto可以代替类型
// for (auto ch : s1)
// {
// cout << ch << " ";
// }
// cout << endl;
//
// // 修改
// for (auto& ch : s1)
// {
// ch++;
// }
//
// for (auto ch : s1)
// {
// cout << ch << " ";
// }
// cout << endl;
//
// for (auto e : It)
// {
// cout << e << " ";
// }
// cout << endl;
//
// int i = 1;
// int y = i;
// //自动推导类型
// auto z = y; //int
// auto x = 1.1; //double
// auto n = &i; //int*
// int& r1 = i;
// auto r2 = r1; //int
// auto& r3 = r1; //int&
//
// int a[] = { 1,2,3,4,5,6 };
// for (size_t i = 0; i < sizeof(a)/sizeof(int); i++)
// {
// cout << a[i] << " ";
// }
// cout << endl;
//
// for (auto e : a)
// {
// cout << e << " ";
// }
// cout << endl;
//
// return 0;
//}
C++20开始支持
//void func1(auto x);
//
//auto func3()
//{
// auto y = func4();
// return y;
//}
//
//auto func2()
//{
// auto x = func3();
// //...
// return x;
//}
迭代器(二)

反向迭代器

Const 无法调用迭代器

这种方法const就能使用迭代器,但不能修改

const反向迭代器

int main()
{
string s1("hello world");
string::reverse_iterator rit = s1.rbegin();
while (rit != s1.rend())
{
cout << *rit << " ";
++rit;
}
cout << endl;
const string s2(s1);
//string::const_iterator it1 = s2.begin();
auto it1 = s2.begin();
while (it1 != s2.end())
{
//*it1 += 1;
cout << *it1 << " ";
++it1;
}
cout << endl;
//string::const_reverse_iterator rit1 = s2.rbegin();
auto rit1 = s2.rbegin();
while (rit1 != s2.rend())
{
cout << *rit1 << " ";
++rit1;
}
cout << endl;
return 0;
}
string****类对象的容量操作

注意:
- 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不会改变容量大小。

size,length,max_size,capacity,clear基本用法
int main()
{
string s1("hello world");
//size和length结果是一样的
cout << s1.size() << endl;
cout << s1.length() << endl;
//看最大开辟空间,无意义
cout << s1.max_size() << endl;
//空间大小
cout << s1.capacity() << endl;
cout << endl << endl;
//清除空间,让size变成0
s1.clear();
cout << s1.size() << endl;
cout << s1.capacity() << endl;
return 0;
}
reserve 提前开空间,避免扩容的操作
// reserve 保留 预留
// reverse 反向 翻转
int main()
{
string s1;
// 提前开空间,避免扩容
s1.reserve(200);
size_t old = s1.capacity();
cout << "capacity:" << old << endl;
for (size_t i = 0; i < 200; i++)
{
s1 += 'x';
if (s1.capacity() != old)
{
cout << "capacity:" << s1.capacity() << endl;
old = s1.capacity();
}
}
string s3("11111111");
string s4("111111112222222222222222222222222222222222222222222");
cout << sizeof(s3) << endl;
return 0;
}
resize

int main()
{
string s1("11111111111111111111");
cout << s1 << endl;
cout << s1.size() << endl;
cout << s1.capacity() << endl;
//删除
//<size
s1.resize(15);
cout << s1 << endl;
cout << s1.size() << endl;
cout << s1.capacity() << endl;
//插入
//size< <capacity
//把空间扩容到25,并把后面空间全部插入x; s1.resize(25)如果是这样,那么插入\0
s1.resize(25,'x');
cout << s1 << endl;
cout << s1.size() << endl;
cout << s1.capacity() << endl;
//<capacity
//扩容到40,并插入x
s1.resize(40,'x');
cout << s1 << endl;
cout << s1.size() << endl;
cout << s1.capacity() << endl;
return 0;
}
string****类对象的修改操作

push_back尾插一个字符
int main()
{
string s1("hello world");
//尾插字符
s1.push_back(',');
s1.push_back('x');
cout << s1 << endl;
return 0;
}
append
//int main()
//{
//
// //尾插字符串
// //插入字符串
// s1.append("orld");
// cout << s1 << endl;
//
// //插入十个感叹号
// s1.append(10, '!');
// cout << s1 << endl;
//
// //插入函数
// string s2("hello,wuguo");
// s1.append(s2.begin(), s2.end());
// cout << s1 << endl;
//
// //插入第六个函数之后的字母
// string s3("hello,wuguo");
// s1.append(s2.begin()+6, s2.end());
// cout << s1 << endl;
//
// return 0;
//}
operator+=
// //直接+=,唯一真神
// string s4("hello");
// s4 += ',';
// s4 += "world";
// cout << s4 << endl;
insert
//int main()
//{
// //Insert相当于插入
// string s1("hello,world");
// //后面的数据就是往后面进行挪动的
// s1.insert(5, "xxxxx");
// cout << s1 << endl;
//
// return 0;
//}
erase
相当于删除

replace
//int main()
//{
// //replace相当于替换
// string s1("hello,world");
// cout << s1 << endl;
// s1.replace(5, 1, "%%");
// cout << s1 << endl;
//
// return 0;
//}

加上find就能把空格也能替换了

find的默认位置是从0开始找的,我们给什么值就从什么位置开始找。
c_str

rfind
int main()
{
string s3("test.cpp");
//现在我们想将后缀取出来
//那么我们后缀的特征就是前面有一个点,以点进行区分操作
//那么这个时候就可以使用rfind了
size_t pos = s3.rfind('.');
if (pos != string::npos)//找到的话
{
//这个时候我们就找到位置了,那么我们就要利用substr这个从pos位置开始取子串
string sub = s3.substr(pos);//从pos位置开始取;
cout << sub << endl;
}
}
find就是正向找,rfind就是倒着找。
find_first_of
// std::string str("Please, replace the vowels in this sentence by asterisks.");
// std::size_t found = str.find_first_of("aeiou");
// while (found != std::string::npos)
// {
// str[found] = '*';
// found = str.find_first_of("aeiou", found + 1);
// }
//
// std::cout << str << '\n';
//
// return 0;
//}

只要你这个字符串里面有我给的这个字符串里面任意一个字符的话,我们就将这个字符变成*。
find_last_not_off
int main()
{
std::string str("Please, replace the vowels in this sentence by asterisks.");
cout << str << endl;
std::size_t found = str.find_first_not_of("aeiou");
while (found != std::string::npos)
{
str[found] = '*';
found = str.find_first_not_of("aeiou", found + 1);
}
std::cout << str << '\n';
return 0;
}
保留元音字母,其他字母全部屏蔽掉,只有aeiou留下来了。
substr
从pos位置取len个字符,然后将这几个衣服构成资格子串string
// string s3("test.cpp.zip");
// size_t pos = s3.rfind('.');
// if (pos != string::npos)
// {
// string sub = s3.substr(pos);
// cout << sub << endl;
// }
to_string
将数据转换为字符串
//int main()
//{
// string s3 = to_string(11.11);
//
// string s1, s2;
// cin >> s1 >> s2;
// cout << s1 << endl;
// cout << s2 << endl;
//
// return 0;
//}
string类非成员函数

getline
遇到#号才停止

总结
常用的:构造、迭代器、容量里面的几个。
