So i'm just starting to learn c++ and i'm curious if its a way to formate your output with cout so it will look nicely and structured in columns
for example.
string fname = "testname";
string lname = "123";
double height = 1.6;
string fname2 = "short";
string lname2 = "123";
double height2 = 1.8;
cout << "Name" << setw(30) << "Height[m]" << endl;
cout << fname + " " + lname << right << setw(20) << setprecision(2) << fixed << height << endl;
cout << fname2 + " " + lname2 << right << setw(20) << setprecision(2) << fixed << height2 << endl
The output looks like this:
Name Height[m]
testname 123 1.60
short 123 1.80
I want it to look like this:
Name Height[m]
testname 123 1.60
short 123 1.80
The problem i'm trying to solve is that i want to place height at a specific position from name but depending what length of name i take the value of height either gets far away to the right or will be very close to the left. Is there a way to fix this?
First of all, with an output stream like std::cout, you cannot travel back in time and modify output which was already performed. That makes sense -- just imagine std::cout wrote into a file because you launched your program with program.exe > test.txt, and test.txt was on a USB drive which has been disconnected in the meanwhile...
So you have to get it right immediately.
Basically, there are two ways to do so.
You can assume that no entry in the first column will ever be wider than a certain number of characters, which is what you have attempted. The problem is that your setw is at the wrong position and that right should be left. A stream manipulator must be placed before the elements which should be affected. And since you want left-aligned columns, you need left:
cout << left << setw(20) << "Name" << "Height[m]" << endl;
cout << left << setw(20) << fname + " " + lname << setprecision(2) << fixed << height << endl;
cout << left << setw(20) << fname2 + " " + lname2 << setprecision(2) << fixed << height2 << endl;
But this solution is not very general. What if you'll have a name with 21 characters? Or with 30 characters? Or 100 characters? What you really want is a solution in which the column is automatically set only as wide as necessary.
The only way to do this is to collect all entries before printing them, finding the longest one, setting the column width accordingly and only then print everything.
Here is one possible implementation of this idea:
std::vector<std::string> const first_column_entries
{
"Name",
fname + " " + lname,
fname2 + " " + lname2
};
auto const width_of_longest_entry = std::max_element(std::begin(first_column_entries), std::end(first_column_entries),
[](std::string const& lhs, std::string const& rhs)
{
return lhs.size() < rhs.size();
}
)->size();
// some margin:
auto const column_width = width_of_longest_entry + 3;
std::cout << std::left << std::setw(column_width) << "Name" << "Height[m]" << "\n";
std::cout << std::left << std::setw(column_width) << fname + " " + lname << std::setprecision(2) << std::fixed << height << "\n";
std::cout << std::left << std::setw(column_width) << fname2 + " " + lname2 << std::setprecision(2) << std::fixed << height2 << "\n";
The next step of evolution would be generalising the std::vector into a self-written class called Table and iterating that Table's rows in a loop in order to print the entries.
string fname = "testname";
string lname = "123";
double height = 1.6;
string fname2 = "short";
string lname2 = "123";
double height2 = 1.8;
cout << left << setw(30) << "Name" << left << "Height[m]" << endl;
cout << left << setw(30) << fname + " " + lname << right << setw(6) << setprecision(2) << fixed << height << endl;
cout << left << setw(30) << fname2 + " " + lname2 << right << setw(6) << setprecision(2) << fixed << height2 << endl;
Related
so I have a structure array with various variables.
struct Data
{
char name[11];
int ID;
int life;
int date;
float avgWindSpeed;
float avgRainFall;
int tornadoes;
int stormCategory;
};
I am looking to sort all the information based on char name[11]. The data that is stored in struct Data comes from a file named storms.txt. Currently, I have everything to make up perfectly but still struggling with sorting everything alphabetically. Also, I named my ofstream outfile and counter contains the total number of storms inside the file.
My current code is:
//--------------------------------------------------------------------------------------------------------------------------------------------------
//Start of Hurricane Level 1
int totalLevel1 = 0; //Will hold the number of storms that are level 1
//This is just setting the top part of the chart
outfile << setw(70) << "Hurricane Level 1" << endl << endl;
outfile << "Name" << setw(10) << "ID" << setw(20) << " Life " << setw(20) << " Average " << setw(20) << " Average " << setw(20) << "Tornadoes" << setw(19) << " Date " << endl;
outfile << " " << setw(10) << " " << setw(20) << "in days" << setw(20) << "wind speed" << setw(20) << "rain fall" << setw(20) << " spawned " << setw(20) << " " << endl;
outfile << endl << endl;
float avgLifeSpan, avgRainFall, avgTornadoes, avgWindSpeed, life = 0, rain= 0, tornado= 0, wind= 0;
//Starting to process the information and printing it in its proper location
for(int i = 0; i < counter; i++)
if(hurricanes[i].stormCategory == 1)
{
totalLevel1++;
life = life + hurricanes[i].life;
rain = rain + hurricanes[i].avgRainFall;
tornado = tornado + hurricanes[i].tornadoes;
wind = wind + hurricanes[i].avgWindSpeed;
outfile << hurricanes[i].name << setw(5) << hurricanes[i].ID << setw(15) << hurricanes[i].life << setw(21) << hurricanes[i].avgWindSpeed
<< setw(20) << hurricanes[i].avgRainFall << setw(19) << hurricanes[i].tornadoes << setw(21) << hurricanes[i].date << endl;
}
//Printing the extra information for HURRICANE LEVEL 1
outfile << endl << endl << "Total number of Level 1 hurricanes is " << totalLevel1 << "." << endl;
outfile << "Average Life span in days of Level 1 hurricanes is " << life / float(totalLevel1) << "." << endl;
outfile << "Average rain fall for Level 1 hurricanes is " << rain / float(totalLevel1) << "." << endl;
outfile << "Average tornadoes spawned for Level 1 hurricanes is " << tornado / float(totalLevel1) << "." << endl;
outfile << "Average wind speed for Level 1 hurricanes is " << wind / float(totalLevel1) << "." << endl;
outfile << endl << endl;
//End of the Hurricane Level 1
//--------------------------------------------------------------------------------------------------------------------------------------------------
How to do I make so that everything that gets printed out on the output file is sorted alphabetically with its correct information? Could someone give me some suggestions?
It depends on how you've defined hurricanes. If it is a C array, then you'll be wanting something like this:
std::sort(hurricanes, hurricanes + counter,
[](const Data& a, const Data& b) { return std::strcmp(a.name, b.name) < 0; });
If however it is a std::vector or std::array, then...
std::sort(hurricanes.begin(), hurricanes.end(),
[](const Data& a, const Data& b) { return std::strcmp(a.name, b.name) < 0; });
I don't see what type of container you use ( I suggest to use std::vector), but you may do couple of nice things to make you life easier in this code.
First overload operators in Data structure like:
ostream& operator<<(ostream& os, const Data& a_data) for easily sending your struct to ostream (without need of encapsulating all it's members).
bool T::operator <(const T2 &b) const; , bool T::operator >(const T2 &b) const; : for comparison in standard algorithms.
Take look at reference : link You will write it only once but could use it in every part of program.
Second suggestion is to use std::sort algorithm to sort your data structure.
std::sort(hurricanes.begin(), hurricanes.end(), greater<Data>());
Syntax of your code will be much easier to understand and read for you wen you come back to project in 6 (or so) months.
I want to display the dollar sign next to its value in the second column, but if I convert the value into a string, the setprecision doesn't work and it displayed more decimals than I would like. Currently the formatting doesn't look good.
My current code:
string unit = "m";
double width = 30.123;
double length = 40.123;
double perimeter = 2 * width + 2 * length;
double area = width * length;
double rate = (area <= 3000) ? 0.03 : 0.02;
double cost = area * rate;
const int COLFMT = 20;
cout << fixed << setprecision(2);
cout << setw(COLFMT) << left << "Length:"
<< setw(COLFMT) << right << length << " " << unit << endl;
cout << setw(COLFMT) << left << "Width:"
<< setw(COLFMT) << right << width << " " << unit << endl;
cout << setw(COLFMT) << left << "Area:"
<< setw(COLFMT) << right << area << " square" << unit << endl;
cout << setw(COLFMT) << left << "Perimeter:"
<< setw(COLFMT) << right << perimeter << " " << unit << endl;
cout << setw(COLFMT) << left << "Rate:"
<< setw(COLFMT) << right << rate << "/sqaure" << unit << endl;
cout << setw(COLFMT) << left << "Cost:"
<< setw(COLFMT) << right << "$" << cost << endl;
Produces this poorly formatted output:
Length: 40.12 m
Width: 30.12 m
Area: 1208.63 square m
Perimeter: 140.49 m
Rate: 0.03/square m
Cost: $36.26
"Currently the formatting doesn't look good."
That's because std::right pertains to what follows it, in your case "$". So the dollar sign is right-aligned and not the value that follows on afterwards.
What you want is the fully formatted monetary value "$36.26" to be right aligned. So build that up as a string first with stringstream.
stringstream ss;
ss << fixed << setprecision(2) << "$" << cost;
cout << left << "Cost:" << setw(COLFMT) << right << ss.str() << endl;
I'm trying to make a receipt, andbalways want the " kg" to be ONE SPACE after the weight, and also "$" just before both 'costperkg' and 'totacost' Initially using setw to format the output, could not get it to work, got it done with ostringstream. I Can anyone explain why does pushing double quote string does not work?
This one does not work :
int main()
{
string item = "A" ;
double weight = 2.00 ;
double costperkg = 1.98 ;
double totalcost = 3.96 ;
cout << fixed << showpoint << setprecision(2);
cout << setw(14) << left << "ITEM" << setw(16) << "WEIGHT" << setw(18) << "COST/kg"
<< setw(14) << "COST" << endl ;
cout << setw(14) << left << item << setw(16) << weight << "kg" << setw(18) << "$"
<< costperkg << setw(14) << "$" << totalcost << endl << endl ;
}
This one works:
ostringstream streamweight, streamcostperkg, streamtotalcost;
streamweight << fixed << showpoint << setprecision(2) << weight ;
streamcostperkg << fixed << showpoint << setprecision(2) << costperkg ;
streamtotalcost << fixed << showpoint << setprecision(2) << totalcost ;
string strweight = streamweight.str() + " kg" ;
string strcostperkg = "$" + streamcostperkg.str() ;
string strtotalcost = "$" + streamtotalcost.str() ;
cout << setw(14) << left << item << setw(16) << strweight << setw(18) << strcostperkg
<< setw(14) << strtotalcost << endl << endl ;
The expected result is :
ITEM WEIGHT COST/kg COST
A 2.0 kg $1.98 $3.96
What I got instead is :
ITEM WEIGHT COST/kg COST
A 2.00 kg$ 1.98$ 3.96
Why does the setw one not work? and also for those viewing on phone, the first character from first and second life of every word should align on the first letter (A, 2, $, $)
OP suspected the std::setw() not to work. IMHO, OP is not aware that the setw() does exactly what's expected but the formatting considers as well the std::left manipulator which makes all following output left aligned. (The left alignment becomes effective in combination with setw() only.)
Example:
#include <iostream>
#include <iomanip>
// the rest of sample
int main()
{
std::cout << '|' << std::setw(10) << 2.0 << "|kg" << '\n';
std::cout << std::left << '|' << std::setw(10) << 2.0 << "|kg" << '\n';
// done
return 0;
}
Output:
| 2|kg
|2 |kg
Live Demo on coliru
(A possible fix is exposed in the question by OP her/himself.)
I'm trying to properly format a table so that it prints out values below each column, beginning with the first character of that column. I've had success formatting three columns, but I'm unable to figure out how to format the K Count and LM Count columns so that they are printed out in a neat fashion.
What are some corrections I can make to the while loop portion of the code so that the K count and LM count columns are printed out neatly?
void printTable(const vector<int>& z, const vector<long>& x, const
vector<long>& y,
const vector<int>& a, const vector<int>& b)
{
ostringstream ss;
ss << "\n\n\n" << setw(10) << left << "Digits" << "Input Numbers "
<< setw(11) << right << "K Output " << setw(6)
<< right << "K Count " << setw(10) << right << "LM Output " << setw(6)
<< right << "LM Count" << endl;
int i = 0, n = 0;
while (i < 5)
{
string q = to_string(z[2*n]) + " x " + to_string(z[abs(2*n + 1)]);
string r = to_string(x[i]);
string s = to_string(a[i]);
string t = to_string(y[i]);
string u = to_string(b[i]);
ss << setw(10) << left << (i+1) << q
<< setw(16) << right << r
<< setw(11) << right << s
<< setw(12) << right << t
<< setw(10) << right << u << endl;
i++;
n++;
}
string r = ss.str();
cout << r;
}
You're printing the following:
- Digits left aligned over 10 chars
- Directly followed by the input number without specifying the width
- K output right aligned over 16 chars
You should instead specify the width of the input numbers as well.
Try this:
ss << setw(10) << left << (i+1) <<
setw(16) << left << q <<
setw(10) << right << s <<
setw(12) << right << t <<
...
The exact width of each column may not be correct. Try it out yourself.
To fix K Count output, you should reset the cursor to align left after setting the width for the previous result, then shift back right. Something like this should do what you want.
ss << setw(10) << left << (i+1) << right
setw(16) << left << q << right <<
setw(11) << left << r << right <<
setw(12) << left << s << right <<
setw(12) << left << t << right <<
setw(10) << left << u << right << endl;
I cannot seem to get the "full"
to display the concatenation of First and last.
It compiles but when I run it it will appear blank.
Can you tell me why?
Have tried to figure it our for hours.
Here are my declerations
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
#define tax 0.30
#define parking_deductions 10.00
#define overtime_hours 40
#define max_hours 60
#define max_pay 99
string namestring( string first, string last, string full);
I'm attempting to pass this module to my main
string namestring(string first, string last, string full)
{
//input name
cout << "What is your first name? " << endl;
cout << "first name: " << endl;
cin >> first;
cout << "What is your last name? " << endl;
cout << "last name: " << endl;
cin >> last;
//process name
full = last + " " + first;
return full;
}
By calling it like so
namestring(first, last, full );
Where I expect the full name input by the user to be displayed below
cout << left << fixed << " " << "Reg." << " " << " Ovt." << " Hourly" << " Net" << " " << " Gross" << endl;
cout << left << fixed << setprecision(2) << setw(10) << "Name " << " Hours" << " Hours" << " Rate" << " Pay" << " Taxes" << " Deduct" << " Pay" << endl;
cout << left << fixed << setprecision(2) << setw(10) << "====================" << " " << "=====" << " " << "=====" << " " << "=====" << " " << "======" << " " << "======" << " " << " " << "========" << " " << "=======" << endl;
cout << left << setprecision(2) << setw(20) << full << right << " " << right << setw(4) << hours << right << " " << right << overtime << " " << right << pay << " " << right << net_pay << " " << right << taxs << " " << right << parking_deductions << " " << right << gross_pay << right << endl;
cout << endl;
cout << endl;
I'm assuming the goal here is to get the following 3 strings,
First Name
Last Name
Full Name
To do this, you would need to pass the arguments by reference, not by value:
void namestring(string& first, string& last, string& full)
{
//input name
cout << "What is your first name? " << endl;
cout << "first name: " << endl;
cin >> first;
cout << "What is your last name? " << endl;
cout << "last name: " << endl;
cin >> last;
//process name
full = last + " " + first;;
}
There is also no need to return a string if you pass the "full" string by reference, since the function will fill it for you.
string namestring(string first, string last, string& full)
//input name
{
cout << "What is your first name? " << endl;
cout << "first name: " << endl;
cin >> first;
cout << "What is your last name? " << endl;
cout << "last name: " << endl;
cin >> last;
//process name
full = last + " " + first;
return full;
}
You are passing the full by value. So it's the local copy of the function which is modified. You need it to pass by reference.
If you also want the first and last value you also need to pass it by reference.