C++分配后字符串大小未更新

C++ string size not updated after assignment

本文关键字:更新 字符串 分配 C++      更新时间:2023-10-16
int main(int argc, char const *argv[])
{
    const char *s1 = "hello";
    string s2;
    s2 = s1;
    s2.reserve(10);
    s2[5] = '.';
    s2[6] = 'o';
    s2[7] = '';
    cout << "[" << s1 << "] [" << s2 << "]" << endl;
    return 0;
}

上面的代码无法正确打印s2。它不是hello.o而是始终打印hello。似乎s2的大小总是在第一次分配后保持在 5。为什么会这样?

operator[] 不会调整字符串的大小。你用索引 5、6 和 7 对它的调用超出了范围和未定义的行为。使用 resize 将字符串设置为特定大小,或者push_backoperator+=追加字符。

另请注意,您不需要手动将std::string端零。类将自行处理。尽管如果您真的想要它们,则可以在其中嵌入零,并且它们将被视为字符串长度的一部分。

s2.reserve(10);根本不会增加字符串,它只是告诉容器为至少 10 个字符保留足够的内存。它不会用任何东西填充保留的空间。

因此,当你索引它时s2[5]你基本上索引在"使用"字符串的边界之外(即它的大小),它是未定义的行为。

要调整大小,可以使用 s2.resize(10); 。这将适当地分配和填充字符串,它的大小为 10 。要同时分配和插入字符,您还可以使用 push_back()operator+= .

附带说明:不需要s2[7] = '';string类在内部管理方法(如c_str()等)所需的任何 NUL 终止。您无需自己添加 NULL。

你应该使用s2.resize()而不是s2.reserve()

std::string::reserve只分配内存,但不调整字符串的大小。在您的示例中:

s2 = s1;         // Resize string to 6 characters
s2.reserve(10);  // Allocate another 4 char, but not resize
s2[5] = '.';     // Write '.' to some memory, but the string is still not resized.

简单的解决方法是使用std::string::resize而不是reserve

简短回答:使用调整大小(10)而不是保留(10)

长答案:在 std::string 的实现中,有两个变量大小和容量。容量是已为字符串分配的内存量。大小是字符串中允许的有效元素(在您的情况下为 char)的数量。请注意,容量将始终小于或等于大小。当您调用 reserve() 时,您正在更改容量。当您调用 resize() 时,您可能不仅会更改大小,而且如果大小>容量,您还将更改容量,然后应用此公式:

if (size > capacity){
capacity = max(size, capacity*2); //Why multiply capacity by 2 here? This is to achieve amortized O(1) while resizing
}

下面是 OP 想要的代码示例,以及更多代码,以便更好地解释大小和容量

#include <iostream>
#include <string.h>
using namespace std;
int main(int argc, char const *argv[])
{   const char *s1 = "hello";
    string s2;
    s2 = s1;
    cout << "length of s2 before reserve: " << s2.length() << endl;
    cout << "capacity of s2 before reserve: " << s2.capacity() << endl;
    s2.reserve(10);
    cout << "length of s2 after reserve: " << s2.length() << endl; //see how length of s2 didn't change?
    cout << "capacity of s2 after reserve: " << s2.capacity() << endl;
    s2.resize(8); //resize(10) works too, but it seems like OP you only need enough size for 8 elements
    cout << "length of s2 after resize: " << s2.length() << endl; //size changed
    cout << "capacity of s2 after resize: " << s2.capacity() << endl; //capacity didn't change because size <= capacity
    s2[5] = '.';
    s2[6] = 'o';
    s2[7] = '';
    cout << "[" << s1 << "] [" << s2 << "]" << endl;
    // You're done
    // The code below is for showing you how size and capacity works.
    s2.append("hii"); // calls s2.resize(11), s[8] = 'h', s[9] = 'i', s[10] = 'i', size = 8 + 3 = 11
    cout << "length of s2 after appending: " << s2.length() << endl; // size = 11 
    cout << "capacity of s2 after appending: " << s2.capacity() << endl; //since size > capacity, but <= 2*capacity, capacity = 2*capacity 
    cout << "After appending: [" << s1 << "] [" << s2 << "]" << endl;
    return 0;

结果:

length of s2 before reserve: 5
capacity of s2 before reserve: 5
length of s2 after reserve: 5
capacity of s2 after reserve: 10
length of s2 after resize: 8
capacity of s2 after resize: 10
[hello] [hello.o]
length of s2 after appending: 11
capacity of s2 after appending: 20
After appending: [hello] [hello.ohii]