Can strings and integers/floats be mixed when formatting via ostringstream - c++

I'm trying to fully understand how to use ostringstream to modernize some code that uses sprintf. The problem is in replacing test code that generates random or sequential data. Here's a simplified example:
char num[6], name[26];
sprintf(num, "%05d", i);
sprintf(name, "Customer # %d", i);
Leaving aside the minutia of length calculation, copying the result to the array and null-termination, the num conversion is straightforward:
ostringstream ostr;
ostr << setw(len) << setfill('0') << i;
For example, given i as 123, the result is "00123".
However, for the name, which is actually a mixture of a char-string and an integer, I can't figure how to replicate what sprintf appears to do so easily.
I tried variations of this:
ostr << setw(len) << left << "Customer # " << i << setfill(' ');
Given the same value for i, the result was always "Customer # 123", i.e., the integer always right justified, no matter what combination of left, right or internal, or the placement of the various parts. It seems the only solution (I haven't tried it yet), is to first concatenate the "Customer # " and the i onto a separate ostringstream and then insert that left justified to the ostr variable. Am I missing something? Is there some other way?
Correction: as discussed in the comments, in simplifying the example I overlooked a second sprintf that was actually responsible for right-padding the name. So a second output to the ostringsteam is also needed to accomplish that.

Related

How to format padded signed numbers in a stringstream

I'm trying to format numbers using C++ streams and am having trouble with the sign character being placed after the fill instead of before. When I do this:
std::cout << std::setfill('0') << std::setw(6) << -1;
The output is
0000-1
But what I want is
-00001
With printf I can use a format like "%06d" and it works the way I expect with the sign placed before the zeroes, but I want to get the same effect in a stream and not use the old formatting functions. I can't use C++20 yet either, so std::format isn't available to me yet.
I should have looked a little longer before posting. The answer is the std::internal manipulator, which causes the padding to be done internally within the field. This works correctly:
std::cout << std::internal << std::setfill('0') << std::setw(6) << -1;
-00001

std::dec still outputting memory address to hex?

I have:
std::cout << "Start = " << std::dec << (&myObject) << std::endl;
to output an address in decimal. However, the address is still coming out in hex??
(I am outputting one of these for each of ten members, so I don't want to assign each one to a variable and then std::dec the variable separately)
The hex and dec manipulators are for integers, not pointers. Pointers are always rendered in the form that printf's %p formatter would have used on your system (which is, usually, hexadecimal notation).
This helps to emphasise the fact that pointers and numbers are distinct. You may consider it to be one of the rare cases in which number semantics and number representation are, to some degree, coupled.
The best you can do is to cast the pointer to uintptr_t before streaming it:
std::cout << "Start = " << std::dec << uintptr_t(&myObject) << std::endl;
…but please consider whether you really need to do so.

Why does ostringstream strip NULL?

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;

Right Justifying output stream in C++

I'm working in C++. I'm given a 10 digit string (char array) that may or may not have 3 dashes in it (making it up to 13 characters). Is there a built in way with the stream to right justify it?
How would I go about printing to the stream right justified? Is there a built in function/way to do this, or do I need to pad 3 spaces into the beginning of the character array?
I'm dealing with ostream to be specific, not sure if that matters.
You need to use std::setw in conjunction with std::right.
#include <iostream>
#include <iomanip>
int main(void)
{
std::cout << std::right << std::setw(13) << "foobar" << std::endl;
return 0;
}
Yes. You can use setw() to set the width. The default justification is right-justified, and the default padding is space, so this will add spaces to the left.
stream << setw(13) << yourString
See: setw(). You'll need to include <iomanip>.
See "setw" and "right" in your favorite C++ (iostream) reference for further details:
cout << setw(13) << right << your_string;
Not a unique answer, but an additional "gotcha" that I discovered and is too long for a comment...
All the formatting stuff is only applied once to yourString. Anything additional, like << yourString2 doesn't abide by the same formatting rules. For instance if I want to right-justify two strings and pad 24 asterisks (easier to see) to the left, this doesn't work:
std::ostringstream oss;
std::string h = "hello ";
std::string t = "there";
oss << std::right << std::setw(24) << h << t;
std::cout << oss.str() << std::endl;
// this outputs
******************hello there
That will apply the correct padding to "hello " only (that's 18 asterisks, making the entire width including the trailing space 24 long), and then "there" gets tacked on at the end, making the end result longer than I wanted. Instead, I wanted
*************hello there
Not sure if there's another way (you could simply redo the formatting I'm sure), but I found it easiest to simply combine the two strings into one:
std::ostringstream oss;
std::string h = "hello ";
std::string t = "there";
// + concatenates t onto h, creating one string
oss << std::right << std::setw(24) << h + t;
std::cout << oss.str() << std::endl;
// this outputs
*************hello there
The whole output is 24 long like I wanted.
Demonstration

How do I convert this C line to C++? using cout command

printf("%-8s - %s\n", c->name ? c->name : "", c->help);
I think what you're looking for is
cout << left << setw(8) << (c->name ? c->name : "") << " - " << c->help << endl;
The left and setw(8) manipulators together have the same effect as the %-8s formatting specifier in printf. You will need to #include <iomanip> in order for this to work, though, because of the use of setw.
EDIT: As Matthieu M. pointed out, the above will permanently change cout so that any padding operations print out left-aligned. Note that this isn't as bad as it might seem; it only applies when you explicitly use setw to set up some padding. You have a few options for how to deal with this. First, you could just enforce the discipline that before using setw, you always use either the left or right manipulators to left- or right-align the text, respectively. Alternatively, you can use the flags and setf function to capture the current state of the flags in cout:
ios_base::fmtflags currFlags = cout.flags();
cout << left << setw(8) << (c->name ? c->name : "") << " - " << c->help << endl;
cout.setf(currFlags, ios_base::adjustfield);
This works in three steps. The first line reads the current formatting flags from cout, including how it's currently aligning padded output. The second line actually prints out the value. Finally, the last line resets cout's output flags for internal alignment to their old value.
Personally, I think the first option is more attractive, but it's definitely good to know that the second one exists since it's technically more correct.
If you've got the Boost libraries:
std::cout << boost::format("%-8s - %s\n") % (c->name ? c->name : "") % c->help;