std :: string长度和容量
一旦你创建了字符串,知道它们有多长,通常很有用。这是长度和容量操作发挥作用的地方。我们还将讨论将std :: string转换回C风格字符串的各种方法,因此您可以将它们与期望字符串类型为char *的函数一起使用。
字符串的长度
字符串的长度非常简单 - 它是字符串中的字符数。确定字符串长度有两个相同的函数:
size_type string :: length()const
size_type string :: size()const
//这两个函数都返回字符串中的当前字符数,不包括空终止符。
//示例代码:
string sSource("012345678");
cout << sSource.length() << endl;
//输出:
9
虽然可以使用length()来确定字符串是否包含任何字符,但使用empty()函数更有效:
bool string :: empty()const
//如果字符串没有字符,则返回true,否则返回false。
//示例代码:
string sString1("Not Empty");
cout << (sString1.empty() ? "true" : "false") << endl;
string sString2; // empty
cout << (sString2.empty() ? "true" : "false") << endl;
//输出:
false
true
您可能永远不会使用另外一个与尺寸相关的功能,但为了完整起见,我们将其包含在此处:
size_type string :: max_size()const
//返回允许字符串具有的最大字符数。
//该值将根据操作系统和系统架构而有所不同。
//示例代码:
string sString("MyString");
cout << sString.max_size() << endl;
//输出:
4294967294
字符串的容量
字符串的容量反映了为保存其内容而分配的字符串的内存量。此值以字符串字符测量,不包括NULL终止符。例如,容量为8的字符串可以容纳8个字符。
size_type string :: capacity()const
//返回字符串在不重新分配的情况下可以容纳的字符数。
//示例代码:
string sString("01234567");
cout << "Length: " << sString.length() << endl;
cout << "Capacity: " << sString.capacity() << endl;
//输出:
Length:8
Capacity:15
请注意,容量高于字符串的长度!虽然我们的字符串长度为8,但字符串实际上为15个字符分配了足够的内存!为什么这样做?
这里要认识到的重要一点是,如果用户想要将更多字符放入字符串中而不是字符串具有容量,则必须将字符串重新分配到更大的容量。例如,如果字符串的长度和容量均为8,则向字符串添加任何字符都会强制重新分配。通过使容量大于实际字符串,这为用户提供了一些缓冲空间来扩展字符串,然后才需要重新分配。
事实证明,由于以下几个原因,重新分配是不好的:
首先,重新分配字符串比较昂贵。首先,必须分配新的内存。然后必须将字符串中的每个字符复制到新内存中。如果字符串很大,这可能需要很长时间。最后,必须取消分配旧内存。如果您正在进行许多重新分配,此过程可能会显著降低您的程序速度。
其次,每当重新分配字符串时,字符串的内容将更改为新的内存地址。这意味着字符串的所有引用,指针和迭代器都将变为无效!
请注意,并非总是会为字符串分配容量大于length的情况。考虑以下程序:
string sString("0123456789abcde");
cout << "Length: " << sString.length() << endl;
cout << "Capacity: " << sString.capacity() << endl;
///该计划输出:
Length:15
Capacity:15
(结果可能因编译器而异)。
让我们在字符串中添加一个字符并观察容量变化:
string sString("0123456789abcde");
cout << "Length: " << sString.length() << endl;
cout << "Capacity: " << sString.capacity() << endl;
// 现在添加一个新character
sString += "f";
cout << "Length: " << sString.length() << endl;
cout << "Capacity: " << sString.capacity() << endl;
这会产生结果:
Length:15
Capacity:15
Length:16
Capacity:31
void string :: reserve()
void string :: reserve(size_type unSize)
此函数的第二种风格将字符串的容量设置为至少unSize(可以更大)。请注意,这可能需要重新分配。
如果调用函数的第一个flavor,或者在unSize小于当前容量的情况下调用第二个flavor,函数将尝试缩小容量以匹配长度。这是一个非约束性请求。
示例代码:
string sString("01234567");
cout << "Length: " << sString.length() << endl;
cout << "Capacity: " << sString.capacity() << endl;
sString.reserve(200);
cout << "Length: " << sString.length() << endl;
cout << "Capacity: " << sString.capacity() << endl;
sString.reserve();
cout << "Length: " << sString.length() << endl;
cout << "Capacity: " << sString.capacity() << endl;
输出:
Length: 8
Capacity: 15
Length: 8
Capacity: 207
Length: 8
Capacity: 207
这个例子展示了两件有趣的事情 首先,虽然我们要求容量为200,但实际上我们的容量为207.容量始终保证至少与您的要求一样大,但可能更大。然后我们请求容量更改以适应字符串。此请求被忽略,因为容量没有变化。
如果您事先知道要通过执行大量字符串操作来构造一个大字符串,这将增加字符串的大小,您可以通过立即将字符串设置为最终容量来避免重新分配字符串多次:
#include <iostream>
#include <string>
#include <cstdlib> //rand()和srand()
#include <ctime> //time()
using namespace std;
int main()
{
srand(time(0)); // 种子随机数发生器
string sString; //长度0
sString.reserve(64); // 保留64个字符
// 用随机小写字符填充字符串
for (int nCount=0; nCount < 64; ++nCount)
sString += 'a' + rand() % 26;
cout << sString;
}
这个程序的结果每次都会改变,但这是一次执行的输出:
wzpzujwuaokbakgijqdawvzjqlgcipiiuuxhyfkdppxpyycvytvyxwqsbtielxpy
我们不是必须多次重新分配sString,而是设置容量一次,然后填充字符串。当通过连接构造大字符串时,这会在性能上产生巨大差异。