目录
- 一、string的定义方式
- 二、 string类对象的容量操作
- 三、string类对象的访问及遍历操作
- 四、string类对象的修改操作
- 五、string类非成员函数
一、string的定义方式
string是个管理字符数组的类,其实就是字符数组的顺序表。
它的接口也是非常多的。本章介绍一些常见使用如文档
string类实现了多个构造函数的重载,常用的构造函数如下
```
default (1) string(); //无参构造
copy (2) string (const string& str); //拷贝str所指的字符序列
substring (3) string(const char* string& str, size_t pos,size_t len =npos); //拷贝str字符串的第pos到最后一个字符
from c-string (4) string (const char* s); //用C-string来构造string类对象,有'\0'
string(const string& s); //拷贝构造
from sequence (5) string (const char* s, size_t n); //拷贝s字符串的前n个进行初始化
fill (6) string (size_t n, char c); //string类对象中包含n个字符c
```
使用示例
//常用
string s1; //无参构造
string s2("羚羊"); //带参构造
string s3("this is a little sheep"); //带参构造
string s4(s2); //拷贝构造
//了解
string s5(7, '#'); //生成7个'#'字符的字符串
string s6(s3, 0, 3); //从s3字符串第0下标拷贝3个字符
string s7(s3, 9); //从s3字符串第8下标拷贝到结尾
二、 string类对象的容量操作
函数名称 | 功能 |
---|---|
size(重点) | 返回字符串有效字符长度 |
length | 返回字符串有效字符长度 |
capacity | 返回空间总大小 |
max_capacity | 返回最大空间 |
empty (重点) | 检测字符串释放为空串,是返回true,否则返回false |
clear (重点) | 清空有效字符 |
reserve (重点) | 为字符串预留空间** |
resize (重点) | 将有效字符的个数该成n个,多出的空间用字符c填充 |
int main()
{
string s1("hello world");
//在string类里等价,常用size
cout << s1.size() << endl;
cout << s1.length() << endl;
//根据编译器的不同结果也不同
cout << s1.max_size() << endl;
cout << s1.capacity() << endl;
cout << s1.size() << endl;
cout << s1.capacity() << endl;
s1.clear();
cout << s1.size() << endl; //只清理字符数据
cout << s1.capacity() << endl; //不清理空间
string s2("hello c++");
//开空间,知道一共需要多少空间一次性开好空间后续就不需要扩容了
//缩容是重新拷贝一块空间把数据拷贝进去,释放掉原空间
s2.reserve(100);
cout << s2.size() << endl;
cout << s2.capacity() << endl;
//开空间+初始化默认\0
s2.resize(100, 'x'); //也可选定初始化字符
cout << s2.size() << endl;
cout << s2.capacity() << endl;
s2.resize(20); //如果只要前20个,把后面数据清掉
cout << s2.size() << endl;
cout << s2.capacity() << endl;
//empty是string的判空函数,我们可以调用strcmp函数来实现,strcmp函数是用于比较两个字符串大小的函数,当两个字符串相等时返回0。
bool empty()
{
return strcmp(_str, "") == 0;
}
return 0;
}
三、string类对象的访问及遍历操作
迭代器在任何容器中都是相通的,虽然各个容器结构不一样,但在用法上都是通用的。
iterator是像指针一样的类型,iterator提供了一种统一的方式访问和修改容器的数据,算法就可以通过迭代器去处理容器中数据。
//正向迭代器
iterator
const iterator
//反向迭代器
reverse_iterator
const_reverse_iterator
函数名称 | 功能 |
---|---|
operator[] (重点) | 返回pos位置的字符,const string类对象调用 |
begin+ end | begin获取第一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器 |
rbegin + rend | rbegin获取最后一个有效字 符的迭代器 + rend获取第一个字符下一个位置的迭代器 |
范围for | C++11支持更简洁的范围for的新遍历方式 |
#include<iostream>
#include<string>
using namespace std;
int main()
{
//[]运算符重载(可读可写)
//[ ]运算符的重载是为了让string对象能像C字符串一样,通过[ ] +下标的方式获取字符串对应位置的字符
char& operator[](size_t i) //只读const char& operator[](size_t i)const
{
assert(i < _size); //检测下标的合法性
return _str[i]; //返回对应字符
}
string s;
string s1("hello world");
cout << s1 << endl; //普通直接打印
//1. 下标+[]遍历,可对字符之间做控制和修改
for (int i = 0; i < s1.size(); i++)
{
s1[5] = '-'; //下标5的位置改为-
cout << s1[i] << ' ';
}
cout << endl;
//2.迭代器
string::iterator it = s1.begin();
while (it != s1.end())
{
cout << *it++ << ' ';
}
cout << endl;
//3.范围for,其实底层就是迭代器
for (auto ch : s1)
{
cout << ch << ' ';
}
cout << endl;
//逆置数组
string s2("hello world");
//写法等价
auto rit = s2.rbegin(); //auto可自动识别类型
string::reverse_iterator rit = s2.rbegin();
while (rit != s2.rend())
{
cout << *rit++ << " ";
}
return 0;
}
四、string类对象的修改操作
函数名称 | 功能 |
---|---|
push_back | 在字符串后尾插字符c |
insert | 插入字符或字符串 |
append | 在字符串后追加一个字符串 |
assign | 覆盖写入字符串 |
erase | 删除字符 |
operator= | 重载后该运算符支持string类的赋值、字符串的赋值以及字符的赋值 |
operator+= (重点) | 在字符串后追加字符串str |
c_str | 返回C格式字符串 |
find + npos | 从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置 |
rfind | 从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置 |
substr | 在str中从pos位置开始,截取n个字符,然后将其返回 |
+=运算符的重载是为了实现字符串与字符、字符串与字符串之间能够直接使用+=运算符进行尾插。
+=运算符实现字符串与字符之间的尾插直接调用push_back函数即可。
1、使用push_back进行尾插
int main()
{
string s1("hello");
s1.push_back(' '); //插入字符
s1.push_back('c');
s1.push_back('p');
s1.push_back('p');
cout << s1 << endl; //hello cpp
return 0;
}
2、使用insert、append、assign插入
int main()
{
string s1("hello world");
//追加
s1.append("abcde");
cout << s1 << endl; //hello worldabcde
s1.assign("1234567");
cout << s1 << endl; //覆盖如上内容改为1234567
//string& insert (size_t pos, const string& str);
s1.insert(0, "hello"); //第0位置插入hello
s1.insert(5, "world"); //第5位置插入world
cout << s1 << endl; //helloworld1234567
//string& insert (size_t pos, size_t n, char c);
s1.insert(0, 7, 'x'); //第0字符插入7个x字符
cout << s1 << endl; //xxxxxxxhelloworld1234567
//void insert (iterator p, size_t n, char c);
s1.insert(s1.begin()+7, 7, 'y'); //第7个位置插入7个x字符
cout << s1 << endl; //xxxxxxxyyyyyyyhelloworld1234567
}
3.使用erase删除
int main()
{
string s1("hello world");
s1.erase(5, 1); //下标第5个位置删除一个字符
cout << s1 << endl;
s1.erase(5); //下标5之后都删除
string s2("hello world");
//两个写法头删
s2.erase(0, 1);
s2.erase(s2.begin());
}
4.截取网站每个部分
int main()
{
string url = "https://cplusplus.com/reference/string/string/?kw=string";
size_t pos1 = url.find("://");
string protocaol;
if (pos1 != string::npos)
{
protocaol = url.substr(0, pos1);
}
cout << protocaol << endl;
string domain;
string uri;
size_t pos2 = url.find('/',pos1+3);
if (pos2 != string::npos)
{
domain = url.substr(pos1 + 3, pos2 - (pos1 + 3));
uri = url.substr(pos2 + 1);
}
cout << domain << endl;
cout << uri << endl;
}
5.+和+=
int main()
{
string s1;
string s2("hello");
//支持string类的赋值
s1 = s2;
cout << s1 << endl; //hello
//支持字符串的赋值
s1 = "world";
cout << s1 << endl; //world
//支持字符的赋值
s1 = 'x';
cout << s1 << endl; //x
string s3;
string s4("hello");
//支持string类的复合赋值
s3 += s4;
cout << s1 << endl; //hello
//支持字符串的复合赋值
s3 += " world";
cout << s3 << endl; //hello world
//支持字符的复合赋值
s3 += '!';
cout << s4 << endl; //hello world!
return 0;
}
五、string类非成员函数
operator+ | 尽量少用,因为传值返回,导致深拷贝效率低 |
---|---|
operator>> (重点) | 输入运算符重载 |
operator<< (重点) | 输出运算符重载 |
getline (重点) | 获取一行字符串 |
relational operators (重点) | 大小比较 |
1.string类中也对>>和<<运算符进行了重载,这就是为什么我们可以直接使用>>和<<对string类进行输入和输出的原因。
istream& operator>> (istream& is, string& str);
ostream& operator<< (ostream& os, const string& str);
int main()
{
string s;
cin >> s; //输入
cout << s << endl; //输出
return 0;
}
2.string类中还对一系列关系运算符进行了重载,它们分别是==、!=、<、<=、>、>=。重载后的关系运算符支持string类和string类之间的关系比较、string类和字符串之间的关系比较、字符串和string类之间的关系比较。
int main()
{
string s1("abcd");
string s2("abde");
cout << (s1 > s2) << endl; //0
cout << (s1 < s2) << endl; //1
cout << (s1 == s2) << endl; //0
return 0;
}
这些重载的关系比较运算符所比较的都是对应字符的ASCII码值。
3.使用>>进行输入操作时,当>>读取到空格便会停止读取,我们将不能用>>将一串含有空格的字符串读入到string对象中。
用法1
可以用getline函数完成一串含有空格的字符串的读取操作。
istream& getline (istream& is, string& str);
getline函数将从is中提取到的字符存储到str中,直到读取到换行符’\n’为止。
int main()
{
string s;
getline(cin, s); //输入:hello world
cout << s << endl; //输出:hello world
return 0;
}
用法2
istream& getline (istream& is, string& str, char delim);
getline函数将从is中提取到的字符存储到str中,直到读取到分隔符delim或换行符’\n’为止。
int main()
{
string s;
getline(cin, s, 'l'); //输入:hello world
cout << s << endl; //输出:hello wor
return 0;
}