I have a string whose last part(suffix) needs to be changed several times and I need to generate new strings. I am trying to use ostringstream to do this as I think, using streams will be faster than string concatenations. But when the previous suffix is greater than the later one, it gets messed up. The stream strips off null characters too.
#include<iostream>
#include<sstream>
using namespace std;
int main()
{
ostringstream os;
streampos pos;
os << "Hello ";
pos = os.tellp();
os << "Universe";
os.seekp(pos);
cout<< os.str() << endl;
os << "World\0";
cout<< os.str().c_str() << endl;
return 0;
}
Output
Hello Universe
Hello Worldrse
But I want Hello World. How do I do this? Is there anyother way to do this in a faster manner?
Edit:
Appending std::ends works. But wondering how it works internally. Also like to know if there are faster ways to do the same.
The string "World" is already null-terminated. That's how C strings work. "World\0" has two \0 characters. Therefore, operator<<(ostream&, const char*) will treat them the same, and copy all characters up to \0. You can see this even more clearly, if you try os << "World\0!". The ! will not be copied at all, since operator<< stopped at the first \0.
So, it's not ostringstream. It's how C strings aka const char* work.
It doesn't strip anything. All string literals in C++ are terminated by NUL, so by inserting one manually you just finish the string, as far as anyone processing it is concerned. Use ostream::write or ostream::put, if you need to do that — anything that expects char* (with no additional argument for size) will most likely treat it specially.
os.write("World\0", 6);
Why do you think a stream operation is faster than a string? And why build the string before outputting to cout?
If you want a prefix to your output you could just do it like this
const std::string prefix = "Hello ";
std::cout << prefix << "Universe" << std::endl;
std::cout << prefix << "World" << std::endl;
Related
in this minimal example there is a weird messing up between the input to a stringstream and the content of a previously used cout:
online gdb:
https://onlinegdb.com/itO69QGAE
code:
#include <string>
#include <iostream>
#include <sstream>
using namespace std;
const char sepa[] = {':', ' '};
const char crlf[] = {'\r', '\n'};
int main()
{
cout<<"Hello World" << endl;
stringstream s;
string test1 = "test_01";
string test2 = "test_02";
s << test1;
cout << s.str() << endl;
// works as expected
// excpecting: "test_01"
// output: "test_01"
s << sepa;
cout << s.str() << endl;
// messing up with previous cout output
// expecting: "test_01: "
// output: "test_01: \nHello World"
s << test2;
cout << s.str() << endl;
// s seems to be polluted
// expecting: "test_01: test_02"
// output: "test_01: \nHello Worldtest_02"
s << crlf;
cout << s.str() << endl;
// once again messing up with the cout content
// expecting: "test_01: test_02\r\n"
// output: "test_01: Hello Worldtest_02\r\nHello World"
return 0;
}
So I am wondering why is this happing?
As it only happens when a char array is pushed into the stringstream it's likely about this... but according to the reference the stringstream's "<<"-operator can/should handle char* (what actually the name of this array stand's for).
Beside that there seems to be a (?hidden, or at least not obvious?) relation between stringstream and cout. So why does the content pollute into the stringstream?
Is there any wrong/foolish usage in this example or where is the dog buried (-> german idiom :P )?
Best regards and thanks
Damian
P.S. My question is not about "fixing" this issue like using a string instead of the char array (this will work)... it's about comprehend the internal mechanics and why this is actually happing, because for me this is just an unexpected behaviour.
The std::stringstream::str() function returns a string containing all characters previously written into the stream, in all previous calls to operator<< (or other output functions). However it seems that you expect that only the last output operation will be returned - this is not the case.
This is analogous to how e.g. std::cout works: each invocation of std::cout << appends the string to standard output; it does not clear the console's screen.
To achieve what you want, you either need to use a separate std::stringstream instance every time:
std::stringstream s1;
s1 << test1;
std::cout << s1.str() << std::endl;
std::stringstream s2;
s2 << sepa;
std::cout << s2.str() << std::endl;
Or better, clear the contents of the std::stringstream using the single argument overload of the str() function:
std::stringstream s;
s << test1;
std::cout << s.str() << std::endl;
// reset the contents of s to an empty string
s.str("");
s << sepa;
std::cout << s.str() << std::endl;
The s.str("") call effectively discards all characters previously written into the stream.
Note, that even though std::stringstream contains a clear() function that would seem a better candidate, it's not analogous to e.g. std::string::clear() or std::vector::clear() and won't yield the effect desired in your case.
Here I am again,
Thanks to "Some programmer dude"'s comment I think I figured it out:
As there is no (null-)termination-symbol related to both char arrays it seems that the stringstream-<<-operator inserts until it stumbles over an null-terminator '\0'.
Either expending both arrays with a \0-symbol (e.g. const char sepa[] = {':', ' ', '\0'}) or terminating the length with e.g. s << string(sepa,2) will do the expected output.
In this specific case above the data seems to lay aligned in memory, so that the next null-terminator will be found inside the cout << "Hello World"-statement. As this alignment is not guaranteed, this will actually result in undefined behaviour, when the termination is missing.
So also two additional "terminating"-arrays like e.g const char sepa[] = {':', ' '}; char[] end_of_sepa = {'\0'}; declared right after the mentioned arrays will result in expected output, eventhough when the rest will be left unchanged... but this is probably not guaranteed and depends on the internal representation in memory.
P.S. As previously written this issue is not about fixing but comprehension. So please feel free to confirm or correct my assumption.
EDIT: Corrected the bold code section.
This question already has answers here:
What exactly does stringstream do?
(4 answers)
Closed 4 years ago.
I'm going to keep this question very simple. I'm learning C++ and I've come across stringstreams. I understand that their main usage is to have variables input into them so they can later output the value they hold using str() as a string. My question is - what's the point of this? This sounds like a very fancy way of just concatenating a bunch of variables in a string object using the + operator. Does it have more to it than that or is it just so it confuses noobs and causes them to fail their exams?
Well, one problem is that you cannot "concatenate a bunch of variables in a string using the + operator" (only other strings or char*s).
So, how are you going to turn all your objects into strings? Unlike Java, C++ does not have any to_string() member convention. On the other hand, every class interested in using iostream will define stream inserters (std::ostream& operator<<(std::ostream& os, const MyClass& foo) and maybe std::istream& operator>>(std::istream& os, MyClass& foo).)
So, you use the stream inserters to convert objects to text. Sometimes you don't want to write to the console or to a file, but instead you want to store it as a string.
Also, using the iostream framework lets you use the manipulators to control precision, width, numerical base, and so on, instead of trying to do all that manually as you construct a string.
Now, that's not to say that the stringstream solution is ideal: in fact, a lot of libraries exist to do the same sort of task better (including at least Boost.Format, Boost.Convert, Boost.Lexical_Cast, and Boost.Spirit just in Boost.)
If you have:
int a = 3;
std::string str = "hello";
MyObject obj;
Then:
std::string concat = a + str + obj;
std::string objstr = obj;
won't work, while:
std::stringstream stream;
stream << a << str << obj;
std::string concat = stream.str();
std::stringstream stream2;
stream2 << obj;
std::string objstr = stream2.str();
Will work (at least if MyObject defines a operator<<). That's the whole point of std::stringstream: make it easy to redirect "anything" to a string.
Any object that can be redirected to a std::ostream (std::fstream, std::cout...) can also be redirected to a std:::stringstream (as it derives from ̀std::ostream too). Then you just need to declare one std::ostream redirection operator (operator<<) and it can be used to redirect the object everywhere (file, console, but also string...).
The whole point is that you could declare a operator+ and operator+= to make it possible to concatenate your object to a std::string. But then, if you also wish to redirect it to a stream (file, cout), you'll have to declare 3 operators (operator+, operator+= and finally operator<< for streams), all doing almost the same thing. In the end, thanks to std::stringstream, having only one single operator (operator<<) is enough to redirect to file, cout and string.
What's the point of stringstream?
It is a flexible and fast stream, and works as a simulator for other (comparatively) slow streams. I use stringstream for lots of different things.
My favorite use is for test. I create a std::istream and fill it with test data. This allows me to create the test data 'file' using the same editor with which I code (and no actual file polluting my work dir). Adding more test cases is remarkably less time consuming.
// 012345678901234567890123456789012345678901234567890
std::istringstream iss("7 ((23, 342), (17, 234), (335, 159), (10, 10))");
// ---|^^^^^^^|^v|vvvvvvv|v^|^^^^^^^^|^v|vvvvvv|^
// 1 2 3 4
// echo to user of test
std::cout << "Test Data Input: " << iss.str() << std::endl ;
// code under test starts here ...
int nTowns = 1;
char lparen0 = 2;
iss >> nTowns // NOTE : formatted input drops whitespace
>> lparen0;
// and continues with echo of post conversion
std::cout << " 0: " << nTowns << ' ' << lparen0 << std::endl;
// then more of the same - until record is completely read.
I have used stringstream to build a screen update, and use that dynamic changing string to 'measure' the banner width, and compute where to start the placement on the screen so that the banner is centered (or left, or right):
static void centerUpdateScreenBanner( uint64_t gen,
int pdMS,
int changes,
TC_t& tc)
{
// build contents of screen banner update
std::stringstream ss;
ss << std::setw(3) << pdMS << " "
<< std::setw(4) << gen << " "
<< std::setw(4) << changes;
// compute start column placement for centering
int rCol = tc.maxCol -
static_cast<int>(ss.str().size()) +
tc.DfltIndnt-1;
// send banner to terminal device for user info
tc.termRef << Ansi_t::gotoRC(0, rCol) // top right
<< ss.str() << std::flush;
}
Inside this link list, I use a stringstream to absorb and recursively concatenate list nodes info. While this builds recursively, other cout or cerr can proceed un-hindered - as if a 3rd channel.
std::string showR(void) {
std::stringstream ss;
ss << m_payload->show(); // this node
if(m_next) ss << m_next->showR(); // subsequent nodes
return (ss.str());
}
Summary: I have found std::stringstream to be very useful.
In C++, using printf-s I want to write a char array (etc char asd[50]) to console with a specified 50 space
(similar like "%.2d" method at decimals, if the string shorter fill it with spaces....)
Tried %50s and %.50s methods, both of them wronged my charachters....
I can (hardly) accept answers, but then calculat with the fact, i use a charachter array, so its not wrok to cout<
Try this if you find it useful,
#include <iomanip>
void prints(const char * s)
{
cout << std::setfill('0') << std::setw(50) << s;
}
A used a for loop with printfs (using %c) to write it, and after the \0 charachter it write spaces , so problem solved
for(int j=0;j<50;j++)
{
printf("%c",asd[j]);
}
I am trying to convert several values into one string, which is to be used as a filename, however after trying several different methods, I'm a bit stumped.
string reportfile = myarray[0][2] + myarray[0][3] + "report.txt";
cout << reportfile << endl;
ofstream outfile(reportfile);
I've tried to_string and .str(), and I tried to add each of them onto the string separately, still converting the methods mentioned before, but I either did all of it incorrectly, or they it didn't work.
The arrays would contain year and day, I need the reportfile value to be, for example:
201312report.txt
So, how would I go about to converting the two int array items and the text into a single string.
In C++11 you can use std::to_string() for int-to-string conversions:
string reportfile = to_string(myarray[0][2]) + to_string(myarray[0][3]) + "report.txt";
Try this:
#include <sstream> // ^ top of the file
std::ostringstream reportfile;
reportfile << myarray[0][2] << myarray[0][3] << "report.txt";
std::string reportfile_str = reportfile.str();
std::cout << reportfile_str << std::endl;
std::ofstream outfile(reportfile_str.c_str()); // in c++11, ommit the ".c_str()"
This assumes there is an output operation from whatever type is stored in myarray (I assumed it's an integer type).
I've come this far without asking for help, but I've got a problem that I can't seem to fix. I like cryptology, so now that I am learning C++, I want to make programs to encrypt and decrypt strings. I read that the best way is to convert the text to ASCII and go from there, so here is a simple program I made in C++ to try and convert a char variable to ASCII:
#include <iostream>
#include <string>
#include <math.h>
using namespace std;
int main()
{
char strString[1000];
cout<<"Enter you message:"<<endl;
cin>>strString[1000];
string strEncrypt;
int a = 0;
while (strString != '\0')
{
int b = (int)strString[a];
strEncrypt.at(a) = b; //This is where I'm getting an error.
a++;
}
cout<<"Encrypted message:"<<endl;
cout<<strEncrypt<<endl;
}
So, I've tried all 3 things I know to do to troubleshoot (Google, check for missing simicolons, and make sure I'm doing == not =, but this is just something I don't know how to do, not something I'm forgetting (I hope). So, any help would great!
You don't have to change the characters to ASCII they already are. Chars are basically the same as integers in memory.
Now to your question; . If you want to set a character in a string you can do that like this
string[index] = b;
Another thing to be careful for in your code. You are using cin to read the string from the user. This will not let you read messages that have spaces in them and will only read the first word. For example, if the user enters "Love Crypto" cin will only read "Love" and "Crypto" will be ignored. To get the entire line, use getline instead.
As for looping over characters in a string, it's better to do it as follows:
for(int i = 0; i < strString.length(); i++)
{
strString[i] = bla;
}
Again, you're code isn't actually doing anything. It is only reading a letter and then storing a "letter" in another string.
string::at() throws exception if the index passed to at() is out of range. So, if you are getting runtime error then it's expected. Because, your string strEncrypt is initialized to "" and thus the size is 0.
You may try
strEncrypt.reserve(strlen(strString));
Easiest way to actually make the code you have work is change this line strEncrypt.at(a) = b; to this strEncrypt += b; Which will add the characters to the empty string strEncrypt.
Your code doesn't make much sense though as char types are already ascii. You'll have to explain more about what kind of encrypting you are trying to do and maybe we can point you in the right direction.
EDIT: After thinking about what you're trying to do a bit more based on the code you have it seems like you want to print the numeric ascii value of characters. You can do that with just a cast like this:
string input;
cout << "Enter you message:" << endl;
// handle spaces in the message
getline(cin, input);
cout << "String chars as ascii values:" << endl;
cout << "Char: " << "ASCII Code:" << endl;
for (int i = 0; i < input.length(); ++i)
{
// casting the char to an int with (int) will print the ascii code
cout << input[i] << " " << (int)input[i] << endl;
}
On top of the fact that your input is already in ASCII, keep in mind that doing cin >> strString[1000] doesn't limit the input captured to the length of your buffer unless you specifically specify the number of characters to capture for the stream object using setw() or setting it's ios_base::width data member. So your method right now risks buffer overflows.
Secondly, the form of cin >> that you're using will not capture the entire line of input. Instead it will stop at the first white-space or any other delimiting character (or end-of-file if that is reached first). In your case, if you are entering a line like "Hello World", then the syntax you're using will only capture "Hello" and drop "World".
A much better idea would be to use the getline() function with a std::string object if you are wanting to capture a line of input to a string and remove the delimiting newline character without risking buffer overflows ... for instance:
string strString;
getline(cin, strString);
Apart from advises given, when receiving this kind of run-time errors use Cppcheck utility.
It will give you the answer: "Message: Array 'strString[1000]' index 1000 out of bounds".