5
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] = '\0';
    cout << "[" << s1 << "] [" << s2 << "]" << endl;
    return 0;
}

The above code does not print s2 correctly. Instead of hello.o it prints hello always. It seems like the size of s2 remains at 5 always after the first assignment. Why is this so?

0

5 Answers 5

10

operator[] does not resize the string. And your calls to it with indices 5, 6 and 7 are out of range and undefined behavior. Use resize to set the string to a specific size, or push_back or operator+= to append characters.

Also note that you do not need to zero terminate std::string manually. The class will handle that by itself. Although you are allowed to have embedded zeros in there if you really want them, and they will be considered as part of the length of the string.

Sign up to request clarification or add additional context in comments.

4 Comments

Is it undefined? I think the program will get an error at runtime.
@Stalker It might or might not.
@Stalker: Yes, it is undefined behavior. If you want defined out of bounds access (an exception), use at.
Oh, I've just read the document and I found out I was wrong. Sorry about my mistake.
6

s2.reserve(10); doesn't grow the string at all, it just tells the container to reserve enough memory for at least 10 characters. It does't fill the reserved space with anything.

Hence, when you index it s2[5] you essentially index outside the bounds of the "used" string (i.e. its size), it is undefined behaviour.

To resize, you can use s2.resize(10);. This will allocate and fill the string appropriately and it will have a size of 10. To allocate and insert a character at the same time, you could also use push_back() or operator+=.

On a side note: s2[7] = '\0'; is not needed. The string class manages internally any NUL terminations that are needed for methods such as c_str() etc. You don't need to add the NUL yourself.

Comments

4

You should use s2.resize() instead of s2.reserve().

Comments

2

std::string::reserve only allocates memory, but not resizes the string. In your example:

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.

Easy fix is to use std::string::resize instead of reserve.

Comments

0

Short answer: use resize(10) instead of reserve(10)

Long answer: In the implementation of std::string, there are two variables size and capacity. Capacity is how much memory you have allocated for the string. Size is how many valid elements (in your case, char), are allowed in your string. Note that capacity will always be smaller than or equal to size. When you call reserve(), you're changing capacity. When your call resize(), you might NOT only be changing size, but you will also changing capacity if size > capacity, in which this formula would then applies:

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

Here's a code example of what OP wants and some more code for a better explanation of size and capacity

#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] = '\0';
    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;

Result:

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]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.