I am a beginner in C++ and I am currently working with strings.
My question is why when compiling the code I'm providing below, I can get the string's characters when I use index notation, but cannot get the string itself using cout
?
This is the code:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string original; // original message
string altered; // message with letter-shift
original = "abc";
cout << "Original : " << original << endl; // display the original message
for(int i = 0; i<original.size(); i++)
altered[i] = original[i] + 5;
// display altered message
cout << altered[0] << " " << altered[1] << " " << altered[2] << endl;
cout << "altered : " << altered << endl;
return 0;
}
When I run this, the characters in the string altered
are displayed correctly with this line:
cout << altered[0] << " " << altered[1] << " " << altered[2] << endl;
But the string itself is not displayed with this line:
cout << "altered : " << altered << endl;
I would like to know why this happens.
You have not resized your altered
string to fit the length of the original
string before the loop, thus your code exhibits undefined behavior:
altered[i] = original[i] + 5; // UB - altered is empty
To fix this, resize altered
before the loop:
altered.resize(original.size());
Or use std::string::operator+=
or similar to append to altered
:
altered += original[i] + 5;
This way, it can be empty before the loop, it will automatically resize itself to contain appended characters.
The way UB is happening here, is that you're succeeding in writing the data in the static array, which std::string
uses for short string optimization (std::string::operator[]
does no checks if you're accessing this array past the std::string::size()
), but std::string::size()
remains 0
, as well as std::string::begin() == std::string::end()
.
That's why you can access the data individually (again, with UB):
cout << altered[0] << " " << altered[1] << " " << altered[2] << endl;
but cout << aligned
does not print anything, considering simplified operator<<
definition for std::string
looks functionally like this:
std::ostream &operator<<(std::ostream &os, std::string const& str)
{
for(auto it = str.begin(); it != str.end(); ++it) // this loop does not run
os << *it;
return os;
}
In one sentence, std::string
is not aware of what you did to its underlying array and that you meant the string to grow in length.
To conclude, <algoritm>
way of doing this transformation:
std::transform(original.begin(), original.end(),
std::back_inserter(altered), // or altered.begin() if altered was resized to original's length
[](char c)
{
return c + 5;
}
(required headers: <algorithm>
, <iterator>
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With