目录
[元素访问(Element access)](#元素访问(Element access))
介绍
string属于STL(Standard Template Library,标准模板库)中容器的一部分。容器是用来存储和管理数据的对象。
string表示字符串的字符串类。string的出现的时间比STL还要早所以里面的有些接口就会有点冗余。要使用string的话要加上名为<string>的头文件。这是关于使用string的网址:string,这里我就只是简单介绍一下某些接口的使用。
使用
迭代器(Iterator)
迭代器(iterator)是一种用于遍历容器中元素的对象。它提供了一种统一的方式来访问不同类型容器中的元素,无需了解容器的内部实现细节。这是封装的一种体现。
begin,end
begin:返回字符串第一个字符的迭代器,end:返回字符串最后一个字符的迭代器。
如果是空字符串使用它们会返回指向该空字符串起始位置的迭代器。利用它们就可以实现字符串的遍历。例:
cpp
#include <iostream>
#include <string>
using namespace std;
void print(string& s)
{
string::iterator it = s.begin();
while (it != s.end())
{
cout << *it;
it++;
}
}
int main()
{
string s("hello world");
print(s);
return 0;
}//下面会频繁用到print这个函数
大家可能注意到了这个:
第一个it前面有个*号,第二个it后面面有个++。这里大家可能猜到了这就是指针!这里的迭代器也确实可以简单认为是指针,因为string开辟的空间是连在一起的。但是后面得list开辟的空间不是连续的就不能简单认为迭代器是指针。但是后面的list用迭代器遍历也是这样写的因为使用了运算符重载。
如果不用对字符串里的内容修改就可以用cbegin,cend。这时候迭代器就要改为const_iterator。
cpp
int main()
{
string s("hello world");
string::const_iterator it = s.cbegin();
while (it != s.cend())
{
cout << *it;
it++;
}
return 0;
}
rbegin,rend
前面的r其实是reverse("反转""颠倒""逆向"),所以rbegin:返回最后一个字符的迭代器,rend:返回第一个字符的迭代器。这时候迭代器就要改为reverse_iterator。这时就可以实现逆序打印字符串。例:
cpp
int main()
{
string s("hello world");
string::reverse_iterator it = s.rbegin();
while (it != s.rend())
{
cout << *it;
it++;
}
return 0;
}
大家可能好奇为什么不设计--来实现逆序打印。其实是为了保持语言的一致性、清晰性、可维护性。
如果不用对字符串里的内容修改就可以用crbegin,crend。这时候迭代器就要改为const_reverse_iterator。
容量(Capacity)
size,length
以字节为单位返回有效字符串的长度。
size和length的功能是一样的,这是因为string设计的比STL要早原来的string里没有size为了实现统一性就设计了size。使用例子:
cpp
int main()
{
string s("hello world");
cout << s.size();
return 0;
}
capacity
以字节为单位返回当前为字符串分配的存储空间大小。使用例子:
cpp
int main()
{
string s("hello world");
cout << s.capacity();
return 0;
}
empty
这是判断字符串是否为空。为空则真,否则为假。使用例子:
cpp
int main()
{
string s("hello world");
cout << s.empty();
return 0;
}
clear
将字符串里的所有的字符删除。使用例子:
cpp
int main()
{
string s("hello world");
s.clear();
print(s);
return 0;
}
resize
将字符串调整为长度为 n 个字符。
- 如果n小于字符串的长度
如果n小于字符串的长度,会保留第一个到第n个之间的所有字符,后面的字符都会被移除。使用例子:
cpp
int main()
{
string s("hello world");
s.resize(5);
print(s);
return 0;
}
- 如果n大于或等于字符串的长度
如果n大于或等于字符串的长度就会从最后一个字符开辟n - l(字符串的长度)。可以在最后一个字符的后面新增新的字符,也可以不新增。使用例子:
cpp
int main()
{
string s("hello world");
s.resize(15, 'a');
print(s);
return 0;
}
reserve
用于预分配n个字符数量的内存空间以容纳字符串内容,使其能够容纳最多 n 个字符。
如果 n 大于当前字符串的容量,这个函数会使容器增加其容量到 n 个字符(或更多)。其他情况下,它被视为一个非约束性的请求来缩小字符串容量(一般不会缩小)。使用例子:
cpp
int main()
{
string s("hello world");
s.reserve(20);
cout << s.capacity();
return 0;
}
大家可能发现了这里的值是31并不是20。因为扩容是按照固定的倍数扩的编译器具体扩多大是由它决定的。我们想把容量变成20其实对于编译器来说就只是一个建议,编译器可能会扩成20也有可能扩成比它大的某数字。
元素访问(Element access)
operator[]
获取字符串中pos位置的字符,并返回字符串中 pos 位置的字符的引用。
如果访问超出字符串长度的位置,会导致未定义行为。可能出现程序崩溃、产生错误的结果等。这个就很像是数组里的下标运算符。事实上它就是重载了数组里的下标运算符。使用例子:
cpp
int main()
{
string s("hello world");
for (size_t i = 0; i < s.size(); i++)
{
cout << s[i];
}
return 0;
}
at
at和上面的operator[]几乎一样,也是访问字符串里的字符并返回该字符引用。如果访问的位置超出字符串长度就会抛异常。使用例子:
cpp
int main()
{
string s("hello world");
for (size_t i = 0; i < s.size(); i++)
{
cout << s.at(i);
}
return 0;
}
front,back
front,back和上面的begin,end几乎一样只不过,front:返回的是第一个字符的引用,back:返回的是最后一个字符的引用。空字符串里不能使用它们。使用例子:
cpp
int main()
{
string s("hello world");
s.front() = 'A';
s.back() = 'A';
print(s);
return 0;
}
修饰符(Modifier)
对字符串进行各种操作和变换,以满足不同的需求。
opreator+=
在字符串末尾添加字符或字符串,并增加有效长度。该接口会返回字符串类的引用。使用例子:
cpp
int main()
{
string s("hello world");
s += ' ';
s += "abc";
print(s);
return 0;
}
push_back
在字符串末尾添加字符,使有效地将其长度增加一个。使用例子:
cpp
int main()
{
string s("hello world");
s.push_back('a');
print(s);
return 0;
}
insert
在字符串的指定pos位置之前插入字符或字符串。
第一个参数是插入位置的下标,如果插入位置的下标超出字符串长度就会抛异常。第二个参数可以是字符串,可以是字符但要在字符写要插入字符的长度。该接口返回字符串类的引用。使用例子:
cpp
int main()
{
string s("hello world");
const char* str = "---";
s.insert(0, 1, 'a');
s.insert(1,str);
print(s);
return 0;
}
erase
擦除字符串的一部分,减少其有效长度。
第一个参数是要擦处位置的下标,如果擦除位置的下标超出字符串长度就会抛异常 。第二个参数是要删除字符的长度。如果要删除字符的长度不写或超出字符串有效长度就会把后面的所有的字符都删除。使用例子:
cpp
int main()
{
string s("hello world");
s.erase(0, 1);
print(s);
return 0;
}
如果没接len:
pop_back
在字符串末尾删除字符,使有效地将其长度减少一个。使用例子:
cpp
int main()
{
string s("hello world");
s.pop_back();
print(s);
return 0;
}
操作(operation)
对字符串进行一些操作例如查找,复制等。
c_str
该接口会返回一个指向字符数组的指针。使用例子:
cpp
int main()
{
string s("hello world");
const char* p = s.c_str();
printf("%p", p);
cout << endl << p;
return 0;
}
大家可能注意到了cout << p直接就打印了p的内容了,这是因为string里重载了<<。
copy
将字符串里的内容拷贝到字符数组里,需要注意的是并不会拷贝'\0'。该接口返回实际拷贝的字符数。
第一个参数的位置是字符数组指针,第二个参数是要拷贝字符的长度,第三个参数是字符串里开始拷贝位置的下标(默认是0)。使用例子:
cpp
int main()
{
string s("hello world");
char buffer[20];
size_t len = s.copy(buffer, 5);
buffer[len] = '\0';
cout << buffer;
return 0;
}
find
查找pos位置之后第一次出现的字符和字符串。
第一个参数是要查到的字符串或字符,第二个参数是查找的起始位置pos(默认是0)。如果找到会返回该下标位置,否则返回npos。使用例子:
cpp
int main()
{
string s("hello world");
size_t i = s.find('o');
i != s.npos ? cout << "找到了,下标是" << i: cout << "没找到";
return 0;
}
npos:
- 当在字符串的成员函数中作 len 参数的缺省值时,这时意味着"直到字符串的末尾"。
- 作为返回值,它通常用于表示没有匹配。
- 这个常量被定义为值 -1,由于 size_t 是一个无符号整数类型,所以这是该类型的最大可表示值。
rfind
查找pos位置之前第一次出现的字符和字符串。
第一个参数是要查到的字符串或字符,第二个参数是查找的起始位置pos(默认是npos)。如果找到会返回该下标位置,否则返回npos。使用例子:
cpp
int main()
{
string s("hello world");
size_t i = s.rfind('o');
i != s.npos ? cout << "找到了,下标是" << i : cout << "没找到";
return 0;
}
substr
从字符串里提取子字符串。
第一个参数是子字符串开始的位置,第二个参数是提取子字符串的长度(如果不写会从起始位置到字符串结束)。该接口返回字符串类。使用例子:
cpp
int main()
{
string s("hello world");
string str = s.substr(0, 5);
print(str);
return 0;
}
上面我所提到的接口一定要多练习,千万不要只看不练。