How to use setw with objects - c++

I'm trying to format output using the NTL library (a number theory library). One of the objects is the GF2X object, which is a polynomial represented as a string of coefficients. A quick example:
GF2X a = GF2X(5,1);
a++;
cout<<a;
will yield [1 0 0 0 0 1] which is the same as x^5 + 1. My question is about formatting this output using setw. I want to be able to output various length GF2X objects, prepended by a number, and appended with a string. I'd like my output to look like the following:
1: [x x x x x x x x] string here
15: [x x x] string here
I would also settle for the right ] to be aligned, which is what I should probably expect if I'm using setw. However, when i use the code (variable names ommitted for simplicity):
cout << setw(3)<< int <<": "<< setw(35) << GF2X << setw(15) << string << endl;
I get output more like this (some white space removed for compactness)
1: [x x x x x x x x] string here
15: [x x x] string here
In other words, the setw function seems to be treating the entire output of <<GF2X as a single character, and doesn't seem to actually account for the size of the output string. As you can see from the output I've shown you, the left side of the GF2X output is aligned, but the right side isn't, whereas typically, setw seems to align the right side of outputs.

You can do it with a modification to the output operator. I imagine it's written something like this (I don't know anything about this GF2X class, so this is partially psuedo-code:
std::ostream & operator<<(std::ostream & os, const GF2X & x)
{
os << '[';
for (int i=0; i<x.num_elements; ++i)
os << x.get_element(i) << ' ';
return os << ']';
}
The problem is that setw will only operate on that first '[', it doesn't operate on the whole object (it doesn't know what the whole object is). You can fix the operator by writing the whole thing to a string (using stringstream or some other means), and then outputting the string. If modifying the operator is not an option for you, then you will need to use a separate helper function to first convert the object to a string (using a stringstream), then output that string to the stream.
Actually, boost::lexical_cast would come in really handy for you here, since it will do that last for you:
cout << setw(35) << boost::lexical_cast<std::string>(GF2X);

You can use a temporary ostringstream object to hold the output, and then use setw on the string provided (variable names omitted).
ostringstream oss;
oss << GF2X;
cout << setw(3) << x << ": "<< setw(35) << oss.str() << setw(15) << string <<endl;
This formats the entire ostream object, rather than just the first character, and gives the proper output.

Related

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

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.

Change string by index

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.
Explanation
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>)
In your program string altered is empty. It has no elements.
Thus you may not use the subscript operator to access non-existent elements of the string as you are doing
altered[i] = original[i] + 5;
So you can append the string with new characters. There are several ways to do this. For example
altered.push_back( original[i] + 5 );
or
altered.append( 1, original[i] + 5 );
or
altered += original[i] + 5;
As you may not apply the subscript operator for an empty string to assign a value then it is better to use the range-based for loop because the index itself in fact is not used. For example
for ( char c : original ) altered += c + 5;
The size of altered is always zero - by using indexes you are trying to copy values from original to altered at indexes altered does not have. As LogicStuff has said, this is undefined behaviour - it doesn't generate an error because when we use indexes with std::string we are in fact calling an operator on a std::string to access the data field of a string. Using [] operator is defined in the C++ Standard as having no range check - that's why no error was thrown. The safe way to access indexes is to use the at(i) method: altered.at(i) will instead throw a range error if altered.size() <= i
However, I'm going to give this as my solution because it's a "Modern C++" approach (plus shorter and complete).
This is the alternative I would do to what has been given above:
string original = "abc";
string altered = original;
for (auto& c : altered) c += 5; // ranged for-loop - for each element in original, increase its value by 5
cout << altered << endl;
Note the significant reduction in code :-)
Even if I were doing it LogicStuff's way, I would still do it like this:
string original = "abc"
string altered = ""; // this is actually what an empty string should be initialised to.
for (auto c : original) altered += (c+5);
However, I actually don't recommend this approach, because of the way push_back() and string appending / string concatenation work. It's fine in this small example, but what if original was a string holding the first 10 pages of a book to be parsed? Or what if it's a raw input of a million characters? Then every time the data field for altered reaches its limit it needs to be re-allocated via a system call and the contents of altered are copied and the prior allocation for the data field is freed. This is a significant performance impediment which grows relative to the size of original -- it's just bad practice. It would always be more efficient to do a complete copy and then iterate, making the necessary adjustments on the copied string. The same applies to std::vector.

Mapping two prompted values in the same command line to two variables in C++

it is a very simple thing but I didn't know how to look it up on Google so here it goes.
I would like the user to be able to enter values for two variables in the same line:
Enter the values for x and y:
2 4
The values entered are x = 2 and y = 4
I know std::cin just reads the first word given a string... What about std::getline? The problem is that I want numerical data though...
std::cout << "Enter the values for x and y:" << std::endl;
std::string name
std::getline (std::cin,name);
// now what??
std::cout << "The values you entered are x = " << x << " and y = " << y <<std::endl;
Is there any different approach? A simpler way to do it... We could iterate over the string and splitting into different words by studying the position of the space ASCII character, but that would take a lot of time, there must be a built-in library that allows you to do that...
You are over-thinking the problem. std::cin can get values for type int or double directly:
int x, y;
std::cin >> x >> y;

This is not the output i asked for

#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main() {
ofstream w("d:/tester.txt");
int f = 1;
int s = 2;
int t = 3;
string x = "hello";
w << f << endl << s << endl << t << endl << x ;
w.close();
ifstream r("d:/tester.txt");
r >> x;
cout << x << endl ;
s = s + 10 ;
r.close();
/* ofstream wa("d:/tester.txt");
wa << s;
wa.close();*/
}
I always get the output equal to 1 .
Why is this so ? When i asked for the string hello 1 gets displayed .
In fact, it is the output you ask for: you are reading the first string token from the file. And that happens to be the number “1” you wrote on the first line into the file.
The streaming operators don’t magically parse your file for the most suitable token; they are simply reading the next available token. And even if they did, “1” would be a perfectly valid choice for a string.
You store consecutively 1 2 3 in your file, then you fetch the first value from the file. Are you surprised that the value is 1? If you want the other values, you must call the stream in functions more than once.
The first line of tester.txt is f which is 1.
x is a string, so when you read from tester.txt using r>>x you get the first line, which is "1"
When you open a stream, you open it in a top-bottom fashion, this meaning that the stream is positioned in the beginning of the first line.
You wrote:
w << f << endl << s << endl << t << endl << x ;
So line the lines are:
f
s
t
x
And f = 1, so you are getting what you should be getting.
Isn't that what you would expect, or am I missing something?
You put the values "1" "2" "3" "hello" in the stream, in that order.
Then, you stream from that into a string. String spec says that all characters will be copied until the first valid whitespace. It will see "1" as a char, and then stop at the newline. Hence, you will get a string, the string "1";

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