Cpp/C++ Output allingment in one line from right AND left - c++

I need to write ints from the right and strings from the left into a single line and have them line up properly (view output below the code).
Basically I just need a way to write a table only using iostream and iomanip and change the allingment from right for ints to left for strings and back.
Other tips are also appreciated :)
#include <iostream>
#include <iomanip>
using namespace std;
class foo
{
public:
int i;
std::string s;
int j;
foo(int i1,std::string s1,int j1) : i(i1), s(s1),j(j1) {};
};
int main()
{
foo f1(1, "abc",50);
foo f2(100, "abcde",60);
cout << resetiosflags(ios::adjustfield);
cout << setiosflags(ios::right);
cout << setw(6) << "i" << setw(15) << "s" << setw(15) << "j"<<endl;
cout << setw(8) << f1.i << setw(15)
<< resetiosflags(ios::adjustfield) << setiosflags(ios::left) << f1.s <<setw(5)
<< resetiosflags(ios::adjustfield) << setiosflags(ios::right) << setw(15) << f1.j << endl;
cout << setw(8) << f2.i << setw(15)
<< resetiosflags(ios::adjustfield) << setiosflags(ios::left) << f2.s <<setw(5
<< resetiosflags(ios::adjustfield) << setiosflags(ios::right) << setw(15) << f2.j << endl;
/*i s j
1abc 50
100abcde 60*/
return 0;
}
This is the output:
i s j
1abc 50
100abcde 60
And this is what i need:
i s j
1 abc 50
100 abcde 60

Using left and right in the same line isn't a problem. It looks like the issue you have is not allowing for space after the first value. It looks like the setw(5) may have been for that, but since there's nothing printed after it there's no effect. I used 7 to match the 15 total used for the string width.
Maybe something like this would work? Probably best to extract the magic numbers into constants so you can adjust all of them easily in one place. You could also wrap this in an operator<< to contain all the formatting code in one place.
The first line headings offset one to the left looks weird to me, but it matches your example and is easy to adjust if necessary.
#include <iostream>
#include <iomanip>
using namespace std;
class foo
{
public:
int i;
std::string s;
int j;
foo(int i1, std::string s1, int j1) : i(i1), s(s1), j(j1)
{};
};
int main()
{
foo f1(1, "abc", 50);
foo f2(100, "abcde", 60);
cout
<< right << setw(7) << "i" << setw(7) << ' '
<< left << setw(15) << "s"
<< right << "j"
<< endl;
cout
<< right << setw(8) << f1.i << setw(7) << ' '
<< left << setw(15) << f1.s
<< right << f1.j
<< endl;
cout
<< right << setw(8) << f2.i << setw(7) << ' '
<< left << setw(15) << f2.s
<< right << f2.j
<< endl;
return 0;
}
Output:
i s j
1 abc 50
100 abcde 60

Related

How to format right and left justification on the same line?

If I am making a data table to show the results of several functions, how can I use the setw(), left, and right keywords to create a table which is formatted like this:
Height 8
Width 2
Total Area 16
Total Perimeter 20
Notice how the overall "width" of the table is constant (about 20 spaces). But the elements on the left are left justified and the values on the right are right justified.
#include <iostream>
#include <string>
#include <vector>
#include <iomanip>
struct Result
{
std::string Name;
int Value;
};
int main()
{
std::vector<Result> results = { {"Height", 8}, {"Width", 2}, {"Total Area", 16}, {"Total Perimeter", 20} };
for (auto result : results)
{
std::cout << std::setw(16) << std::left << result.Name;
std::cout << std::setw(4) << std::right << result.Value << std::endl;
}
return 0;
}
You could do something like this:
// "Total Perimiter" is the longest string
// and has length 15, we use that with setw
cout << setw(15) << left << "Height" << setw(20) << right << "8" << '\n';
cout << setw(15) << left << "Width" << setw(20) << right << "2" << '\n';
cout << setw(15) << left << "Total Area" << setw(20) << right << "16" << '\n';
cout << setw(15) << left << "Total Perimeter" << setw(20) << right << "20" << '\n';

How to include two calls of >> in one setw?

Take this a minimal working example
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
cout << setw(10) << "aaaaaaa"
<< setw(10) << "bbbb"
<< setw(10) << "ccc"
<< setw(10) << "ddd"
<< setw(10) << endl;
for(int i(0); i < 5; ++i){
char ch = ' ';
if ( i == 0 )
ch = '%';
cout << setw(10) << i
<< setw(10) << i << ch
<< setw(10) << i
<< setw(10) << i
<< setw(10) << endl;
}
return 0;
}
The output is
aaaaaaa bbbb ccc ddd
0 0% 0 0
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4
What I would like to do is to include << i << ch in one field of setw(10) so that columns are aligned properly.
Since we are looking at either ' ' or '%' you can simply calculate statically.
cout << setw(10) << i
<< setw( 9) << i << ch
<< setw(10) << i
<< setw(10) << i
<< setw(10) << endl;
probably combine i and ch in one string, setw wouldn't accept this behavior natively
try this snippet
cout << setw(10) << i
<< setw(10) << std::to_string(i) + ch;
You need to concatenate them into one string, like this:
#include <string>
cout << setw(10) << std::to_string(i) + ch;
in general.
But if you know that i is one character you could use:
cout << setw(9) << i << ch;
which might the case for you, since i seems to be ' ' or '%'.
I'm not sure to understand your need.
You could use some std::ostringstream like e.g.
std::ostringstream os;
os << i << ch << std::flush;
std::cout << setw(10) << os.str();
You could build a string, like James Maa answered

C++ Iomanip lib setfill and setw issues

My Code:
#include <iostream>
#include <iomanip>
using namespace std;
int main () {
int time;
int honolulu, seattle, london, moscow, hongkong, auckland;
cout << "What is the current time in Philadelphia? ";
cin >> time;
honolulu = (time+2400-600)%2400;
seattle = (time+2400-300)%2400;
london = (time+2400+500)%2400;
moscow = (time+2400+800)%2400;
hongkong = (time+2400+1200)%2400;
auckland = (time+2400+1700)%2400;
cout << endl << "Current times in other cities: " << endl;
cout << setw (12) << left << "Honolulu:";
cout << setw (4) << setfill('0') << honolulu << endl;
cout << setw (12) << left << "Seattle:";
cout << setw (4) << setfill('0') << seattle << endl;
cout << setw (12) << left << "London:";
cout << setw (4) << setfill('0') << london << endl;
cout << setw (12) << left << "Moscow:";
cout << setw (4) << setfill('0') << moscow << endl;
cout << setw (12) << left << "Hong Kong:";
cout << setw (4) << setfill('0') << hongkong << endl;
cout << setw (12) << left << "Auckland:";
cout << setw (4) << setfill('0') << auckland << endl;
return 0;
}
Required Output :
What is the current time in Philadelphia? 0415
Current times in other cities:
Honolulu: 2215
Seattle: 1150
London: 9150
Moscow: 1215
Hong Kong: 1615
Auckland: 2115
My output :
What is the current time in Philadelphia? 0415
Current times in other cities:
Honolulu: 2215
Seattle:00001150
London:000009150
Moscow:000001215
Hong Kong:001615
Auckland:0002115
What am I doing wrong? The first line of output, Honolulu: 2215, is correct. But the next lines have leading zeroes. I do not understand why this is happening? Is there a problem with my code or am I misunderstanding how the functions setfill and setw work?
The fill character is "sticky", so it remains in effect until you change it.
In your case, you want 0 as the fill for the numeric fields, but space as the fill for the character fields, so you'll have to set that explicitly, something like this:
cout << setfill(' ') << setw (12) << left << "Seattle:";
Many of the iomanip objects are "sticky", that is, they stick to the stream and affect subsequent lines.
When you have this:
cout << setw (12) << left << "Seattle:";
cout << setw (4) << setfill('0') << seattle << endl;
that is going to leave the setfill active for the next line. So you might instead prefer
cout << setw (12) << setfill(' ') << left << "Seattle:";
cout << setw (4) << setfill('0') << seattle << endl;
As mentioned in other comments many of I/O manipulators are "sticky".
I personally prefer to solve this kind of problem using RAII:
class stream_format_raii {
public:
stream_format_raii(std::ostream &stream)
: stream_(stream)
, state_(NULL) {
state_.copyfmt(stream_);
}
~stream_format_raii() {
stream_.copyfmt(state_);
}
public:
std::ostream &stream_;
std::ios state_;
};
That this class does is backing up your current stream's format upon constructing and setting it back upon destructing.
You can use it this way:
void printCity(std::ostream &os, const std::string name, int time) {
stream_format_raii back(os);
os << std::setw(12) << std::left << (name + ":");
os << std::setw(4) << std::setfill('0') << time;
}
int main() {
// Same as before
printCity(std::cout, "Honolulu", honolulu);
// Same as before
}

Having trouble with iomanip, columns not lining up the way I expect

finishing up a long project and the final step is to make sure my data lines up in the proper column. easy. Only I am having trouble with this and have been at it for longer than i wish to admit watching many videos and can't really grasp what the heck to do So here is a little snippet of the code that I'm having trouble with:
#include <iostream>
#include <iomanip>
using namespace std;
int main(){
cout << "Student Grade Summary\n";
cout << "---------------------\n\n";
cout << "BIOLOGY CLASS\n\n";
cout << "Student Final Final Letter\n";
cout << "Name Exam Avg Grade\n";
cout << "----------------------------------------------------------------\n";
cout << "bill"<< " " << "joeyyyyyyy" << right << setw(23)
<< "89" << " " << "21.00" << " "
<< "43" << "\n";
cout << "Bob James" << right << setw(23)
<< "89" << " " << "21.00" << " "
<< "43" << "\n";
}
which works for the first entry but the bob james entry has the numbers all askew. I thought setw was supposed to allow you to ignore that? What am i missing?
Thanks
It doesn't work as you think. std::setw sets the width of the field only for the next insertion (i.e., it is not "sticky").
Try something like this instead:
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
cout << "Student Grade Summary\n";
cout << "---------------------\n\n";
cout << "BIOLOGY CLASS\n\n";
cout << left << setw(42) << "Student" // left is a sticky manipulator
<< setw(8) << "Final" << setw(6) << "Final"
<< "Letter" << "\n";
cout << setw(42) << "Name"
<< setw(8) << "Exam" << setw(6) << "Avg"
<< "Grade" << "\n";
cout << setw(62) << setfill('-') << "";
cout << setfill(' ') << "\n";
cout << setw(42) << "bill joeyyyyyyy"
<< setw(8) << "89" << setw(6) << "21.00"
<< "43" << "\n";
cout << setw(42) << "Bob James"
<< setw(8) << "89" << setw(6) << "21.00"
<< "43" << "\n";
}
Also related: What's the deal with setw()?
The manipulators << right << setw(23) are telling the ostream that you want
the string "89" set in the right-hand edge of a 23-character-wide field.
There is nothing to tell the ostream where you want that field to start,
however, except for the width of the strings that are output since the
last newline.
And << "bill"<< " " << "joeyyyyyyy" writes a lot more characters to the output
than << "Bob James" does, so the 23-character-wide field on the second line
starts quite a bit to the left of the same field on the first line.
Stream manipulators affect the next input/output value being streamed, and then some manipulators (including setw()) reset afterwards. So you need to set the width and alignment BEFORE you output a text string, not afterwards.
Try something more like this:
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
void outputStudent(const string &firstName, const string &lastName,
int finalExam, float finalAvg, int letterGrade)
{
cout << setw(40) << left << (firstName + " " + lastName) << " "
<< setw(6) << right << finalExam << " "
<< setw(6) << right << fixed << setprecision(2) << finalAvg << " "
<< setw(7) << right << letterGrade << "\n";
}
int main()
{
cout << "Student Grade Summary\n";
cout << "---------------------\n\n";
cout << "BIOLOGY CLASS\n\n";
cout << "Student Final Final Letter\n";
cout << "Name Exam Avg Grade\n";
cout << "--------------------------------------------------------------\n";
outputStudent("bill", "joeyyyyyyy", 89, 21.00, 43);
outputStudent("Bob", "James", 89, 21.00, 43);
cin.get();
return 0;
}
Output:
Student Grade Summary
---------------------
BIOLOGY CLASS
Student Final Final Letter
Name Exam Avg Grade
--------------------------------------------------------------
bill joeyyyyyyy 89 21.00 43
Bob James 89 21.00 43

String formatting (c++)

I tried to format output strings in my console application (like a table)
cout << "\n\n-----------------\n";
cout << setw(8) << left << "F\t|";
cout << setw(8) << left << "x\t|";
cout << "\n-----------------\n";
//...
cout.width(8);
cout.setf(ios::left);
cout << fixed << setprecision(3) << F << "\t|";
cout.width(8);
cout.setf(ios::left);
cout << x << "\t|";
cout << "\n-----------------\n\n";
But as result my output looks like this
What's wrong with my upper string formatting?
I used the same code as you did and got the same output until I removed the \t at the end of the line. See the new code:
cout << "\n\n-----------------\n";
cout << setw(8) << left << "F\t|";
cout << setw(8) << left << "x\t|";
cout << "\n-----------------\n";
//...
cout.width(8);
cout.setf(ios::left);
cout << fixed << setprecision(3) << F << "|";
cout.width(8);
cout.setf(ios::left);
cout << x << "|";
cout << "\n-----------------\n\n";
As already noted, it's the tabs that are causing the problem.
I would not stop at just removing the tabs though. As it stands right now, your code is highly repetitive and next to impossible to maintain. I'd do a (nearly) complete rewrite, with a couple of functions to cut down on the repetition. My first cut would probably look something like this:
// format a value in a field of specified width, followed by a separator
template <class T>
string field(T val, int w, char sep = '|') {
stringstream b;
b << setw(w) << left << fixed << setprecision(3) << val << sep;
return b.str();
}
// generate a separator for a specified number of fields,
// each of a specified width
string sep(int c, int w, char val = '-') {
string s(c * (w + 1), val);
return string("\n") + s + "\n";
}
int main() {
static const int w = 8;
double F = 1.234, x = 3.45;
string s = sep(2, w);
cout << "\n" << s;
cout << field("F", w) << field("x", w) << s;
cout << field(F, w) << field(x, w) << s;
}
Seems to me that this makes the code rather more readable and quite a bit more maintainable. For example, if we decided to display an a and b on the next line, it would seem fairly obvious to add something like:
cout << field(a, w) << field(b, w) << s;
...and we wouldn't have to look very hard to be pretty sure it was going to match up with the previous line. Likewise, if we wanted to change a column width, etc.
You may try:
cout << "\n\n-----------------\n";
cout << setw(8) << left << "F\t\t|"; // insert more tab here
cout << setw(8) << left << "x\t|";
cout << "\n-----------------\n";
//...
cout.width(8);
cout.setf(ios::left);
cout << fixed << setprecision(3) << F << "\t|";
cout.width(8);
cout.setf(ios::left);
cout << x << "\t|";
cout << "\n-----------------\n\n";
The console screen looks suspiciously Windows like.
If you are using Windows, you can use the Win32 API to format output more precisely.
In particular, you can use SetConsoleCursorPosition.
COORD position = {x,y};
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hOut, position);
std::cout<<"This will be printed starting at position x, y"<<std::endl;
Try this:
#include <iostream>
#include <iomanip>
#include <map>
#include <string>
using namespace std;
int main()
{
map< float, float > table =
{
{ 8232.0f, 89.0f },
{ 8232.1f, 89.0f },
{ 8232.2f, 89.0f },
{ 8232.3f, 89.0f },
{ 8232.4f, 89.0f },
{ 8232.5f, 89.0f },
{ 8232.6f, 89.0f },
{ 8232.7f, 89.0f },
{ 8232.8f, 89.0f },
};
const size_t CELL_WIDTH = 25;
const string CELL_LINE( CELL_WIDTH, '=' );
// print the header of table
cout << '|' << CELL_LINE << '|' << CELL_LINE << '|' << endl
<< '|'
<< left << setw( CELL_WIDTH ) << "F" << '|'
<< setw( CELL_WIDTH ) << "R" << "|\n|"
<< CELL_LINE << '|' << CELL_LINE << '|' << endl;
// print the body
// change cout precision
cout << fixed << setprecision( 3 );
for ( auto it : table )
cout << "| " << setw( CELL_WIDTH - 1 ) << it.first
<< "| " << setw( CELL_WIDTH - 1 ) << it.second
<< "|\n";
// print the footer
cout << '|' << CELL_LINE << '|' << CELL_LINE << '|' << endl;
return 0;
}
this is the result: