Formatting stream spaces - c++

I have been trying to use .pushback to format my string so that it prints just a space between every word.
So I was trying to use a .push_back, however that doesn't work with integers.
std::string FormatVehicleString(std::string year,
std::string make,
std::string model,
double price,
double mileage)
{
year.push_back(5);
make.push_back(5);
model.push_back(5);
price.push_back(5);
mileage.push_back(5);
}
Can someone point me in the right direction, is there another value type that will incorporate strings and integers?

One option is to use a std::ostringstream.
std::string FormatCarInfo(std::string year,
std::string make,
std::string model,
double price,
double mileage)
{
std::ostingstream out;
out << year << " ";
out << make << " ";
out << model << " ";
out << price << " ";
out << mileag ;
return out.str();
}
Another option is to use std::to_string.
std::string FormatCarInfo(std::string year,
std::string make,
std::string model,
double price,
double mileage)
{
return ( year + " " + make + " " + model + " " +
std::to_string(price) + " " + std::to_string(mileage) );
}

Related

Finding the max lengths of strings to format a table output

I want to find the max length of specific attributes from a vector of Person objects.
Below is an example of a Person object:
Person::Person(string first_name, string last_name, int the_age){
first = first_name;
last = last_name;
age = the_age;
}
I have a vector that stores Person objects, and I must print all the people out in a table, like so:
First Name Last Name Age
---------- ------------ ----
John Cool-Johnson 15
Paul Bob 1000
2 people
I need to find the max length of each attribute of a Person in order to grow each column according to the maximum length of name or age. How can I do this?
So far, I have tried lambdas using this code:
unsigned int max_name = *max_element(generate(people.begin(),people.end(), [](Person a){return a.getFirstName()})).size();
But I am not sure if this even works at all.
I must use <iomanip>, but I have no clue how it works.
Is there a better way?
Your use of std::max_element() is wrong. It takes 2 iterators for input, which you are not providing to it. It would need to look more like this:
auto max_name = max_element(
people.begin(), people.end(),
[](const Person &a, const Person &b){
return a.getFirstName().size() < b.getFirstName().size();
}
)->getFirstName().size();
Online Demo
Alternatively:
vector<string> names;
names.reserve(people.size());
for(const Person &p : people) {
names.push_back(p.getFirstName());
}
auto max_name = max_element(
names.begin(), names.end(),
[](const string &a, const string &b){
return a.size() < b.size();
}
)->size();
Online Demo
However, since you will probably also want to do the same thing for the Last Name and Age columns, I would suggest simply looping though the people vector manually, keeping track of the max lengths as you go along, eg:
string::size_type max_fname = 10;
string::size_type max_lname = 9;
string::size_type max_age = 3;
for(const Person &p : people)
{
max_fname = max(max_fname, p.getFirstName().size());
max_lname = max(max_lname, p.getLastName().size());
max_age = max(max_age, to_string(p.getAge()).size());
}
Then you can output everything in a table, eg:
cout << left << setfill(' ');
cout << setw(max_fname) << "First Name" << " " << setw(max_lname) << "Last Name" << " " << setw(max_age) << "Age" << "\n";
cout << setfill('-');
cout << setw(max_fname) << "" << " " << setw(max_lname) << "" << " " << setw(max_age) << "" << "\n";
cout << setfill(' ');
for(const Person &p : people)
{
cout << setw(max_fname) << p.getFirstName() << " " << setw(max_lname) << p.getLastName() << " " << setw(max_age) << p.getAge() << "\n";
}
cout << people.size() << " people\n";
Online Demo

How can I stop ostringstream (oss) from adding to/overwriting predefined variables?

I'm relatively new to C++ and have come across the use of ostringstream oss as a way to include variables in an output and set it as a string.
Ex.
string getDate(){
oss << _month << "," << _day << "," << _year ; //date format
string date = oss.str(); //date as a string
return date;
}
My issue is that every time I call the method getDate() through an object, it adds the previously recorded output into, what I believe is called the "stream."
Ex.
//private variables w default values
int _day{-1};
int _month{-2};
int _year{-3};
int main() {
//init objects
Bday nothing{};
Bday Clyde (12,24,1993);
Bday Harry("Harry",11,05,2002);
//outputs
//expected to return default values (-2,-1,-3)
cout << "Default Values: "<< nothing.getDate() << endl;
//expected to return Clyde's date only: 12,24,1993
cout << "Date Only: " << Clyde.getDate() << endl;
// expect to return Harry's date: (11,05,2002)
cout << "Harry's Bday: " << Harry.getDate() << endl;
return 0;
}
But instead the output is the following:
Default Values:
Date Only: -2,-1,-3
Harry's Bday: -2,-1,-312,24,1993
Process finished with exit code 0
Any way to protect the value of oss or at least make it so that it gets updated rather than added to?
If you want to clear your stream, there are two choices.
Use local stream
string getDate(){
std::ostringstream oss;
oss << _month << "," << _day << "," << _year ; //date format
string date = oss.str(); //date as a string
return date;
}
Clear your stream after use
string getDate(){
oss << _month << "," << _day << "," << _year ; //date format
string date = oss.str(); //date as a string
oss.str(""); // clear stream
return date;
}

floats getting rounded to 1 decimal by C++

I'm writting a C++ program that takes user input and put it inside a file. In this case, it takes in a number (eg. 299.99), but C++ rounds it to 300 (used to be doubles) when using doubles and floats 299.9...
My code:
void Bank::deposit(){
std::cout << "You currently have " << getBalance() << " in your account.\nHow much would you like to deposit? Amount: ";
float amount = optionExists(amount);
if(amount < 1){
std::cout << "Invalid Amount!" << std::endl;
deposit();
}
float moneyInBank = getBalance();
setBalance(moneyInBank + amount);
std::cout << "Your balance of " << moneyInBank << " has been increased to " << getBalance() << std::endl;
std::string theLine = getUsername() + "," + getPassword() + "," + getAccountType() + "," + std::to_string(moneyInBank) + "," + std::to_string(getAdmin());
updateFile(theLine, getUsername(), getPassword(), getAccountType(), getBalance(), (getAdmin()));
displayMenu();
}
When I call the getBalance() method it also returns a float, but as I said, only to one decimal...
Here is a snippet from the text file:
[name,password,type,BALANCE,admin]
lisa,mag24#773,C,24.99,0 ---> What I want (manually entered)
lols,23456,L,30,1 ---> What I got when using doubles
mark,passw0rd,S,24509.9,1 ---> What I got when using floats
Extra Notes: I compile using cmake and code with VSCode
This link may help [link][1]
float iBalance = getBalance();
std::cout<< std::setprecision(2)<<iBalance<< endl;
[1]: https://stackoverflow.com/questions/5907031/printing-the-correct-number-of-decimal-points-with-cout#:~:text=You%20have%20to%20set%20the%20'float%20mode'%20to%20fixed.&text=To%20set%20fixed%202%20digits,ios%3A%3Afixed)%3B%20cout.

argument of type * is incompatible with parameter of type *

I'm working on a project for my "Programming I" class, and I am getting a strange error. It's a payroll program that calculates taxes and what-not, and our professor wants us to put some of our functions in separate .cpp files.
I've set it up so that each employee is treated as a struct:
#include <string>
using namespace std;
struct Employee {
string firstName;
string lastName;
string name;
double rate;
double hours;
char status;
double grossPay;
double insurance;
double socialSecurity;
double stateTax;
double federalTax;
double PYE;
double netPay;
};
In my main program, I have an array of seven employees: "employees", and initialize it from a separate text file, but when I try to pass the array to one of my functions in the separate .cpp files, I get this error:
argument of type "Employee *" is incompatible with parameter of type "Employee *"
The thing is, though that only happens on the first two out of three functions, while the third is fine even when commenting out the first two:
int main() {
const int numEmployees = 7;
Employee employees[numEmployees];
cout << "name" << setw(20) << right << "rate" << setw(8) << "hours" << setw(7) << "ins" << setw(7) << "soc" << setw(7) << "state" << setw(7) << "fed" << setw(7) << "net" << endl
<< setw(46) << "sec" << setw(6) << "tax" << setw(8) << "tax" << endl;
fstream data("employees.txt");
for (int i = 0; i < numEmployees; i++) {
data >> employees[i].firstName >> employees[i].lastName >> employees[i].rate >> employees[i].hours >> employees[i].status;
employees[i].name = employees[i].firstName + " " + employees[i].lastName;
}
computeGrossPay(employees, numEmployees); //<-\
computeInsurance(employees, numEmployees); //<- these two are errors
computeFederalTax(employees, numEmployees); //<-- this one is fine
for (int i = 0; i < numEmployees; i++) {
// compute social security withheld as 7% of gross pay
employees[i].socialSecurity = employees[i].grossPay * 0.07;
// compute state tax as 3% of gross pay
employees[i].stateTax = employees[i].grossPay * 0.03;
// Compute PYE (Projected Yearly earnings) as gross-pay times 52.
employees[i].PYE = employees[i].grossPay * 52;
// Compute Net pay as gross-pay minus insurance minus soc-sec minus state-tax minus fed-tax
employees[i].netPay = employees[i].grossPay - employees[i].insurance - employees[i].socialSecurity - employees[i].stateTax - employees[i].federalTax;
}
printPayroll(employees, numEmployees);
}
Here are what each of the functions look like, each in their own separate file:
void computeGrossPay(Employee* employees, int numEmployees) {
// do stuff
}
void computeInsurance(Employee* employees, int numEmployees) {
// do stuff
}
void computeFederalTax(Employee* employees, int numEmployees) {
// do stuff
}
How can I fix this?
EDIT: I believe this may have been a problem with my IDE. I was using Visual Studio, and as other users pointed out, it compiles just fine elsewhere. I think I'll stick to basic text editors until I'm ready for the more advanced IDEs.
I have several remarks about this code. This code is using C-style arrays, and passing it as pointers and pointer size, which is ill-advised. Also, It doesn't use some of the most basic concepts of C++.
I have made some rearrangements - mostly made Employee into a real struct/class, with its own member functions, instead of passing it from outside. Made the array using the std::array (which is preferable over the raw array), and finally, a small touch - made the number of employees a constexpr.
I haven't arranged the input parsing, but actually, Employee needs to be a class, that disallows touching the values of its members from outside, and should have a constructor, which gets all the relevant inputs, instead of what is done now.
Look at this rearranged code:
using namespace std; // I strongly suggest against it!!!!
struct Employee {
string firstName;
string lastName;
string name;
double rate;
double hours;
char status;
double grossPay;
double insurance;
double socialSecurity;
double stateTax;
double federalTax;
double PYE;
double netPay;
void computeAll() // a bad name, but I don't have a better idea now!
{
computeGrossPay();
computeInsurance();
computeFederalTax();
computeSocialSecurity();
computeStateTax();
computePYE();
computeNetPay();
}
private:
void computeGrossPay();
void computeInsurance();
void computeFederalTax();
void computeSocialSecurity();
void computeStateTax();
void computePYE();
void computeNetPay();
};
int main() {
constexpr uint64_t NUM_OF_EMPLOYEES = 7;
std::array<Employee, NUM_OF_EMPLOYEES> employees{};
cout << "name" << setw(20) << right << "rate" << setw(8) << "hours" << setw(7) << "ins" << setw(7) << "soc" << setw(7) << "state" << setw(7) << "fed" << setw(7) << "net" << endl
<< setw(46) << "sec" << setw(6) << "tax" << setw(8) << "tax" << endl;
fstream data("employees.txt");
for (auto& employee : employees)
{
data >> employee.firstName >> employee.lastName >> employee.rate >> employee.hours >> employee.status;
employee.name = employee.firstName + " " + employee.lastName;
employee.computeAll();
}
return 0;
}

Making my own toString() method on c++ struct

I'm used to oveerriding the Java toString() method on my own objects in classes, but I'm not sure where I'm going wrong with the following code:
struct Student {
std::string name;
int age;
double finalGrade;
std::string toString() {
return "Name: " + name + "\n Age: " + age + "\n Final Grade: " + finalGrade;
}
};
I'm only beginning to learn c++ so any advice would be appreciated
In contrast to java, C++ does not offer a predefined "toString"-method that is called implicitly whenever a string representation of an object is requested. So your toString-method will have to be called explicitly then.
In C++, however, something similar is available by overriding the operator << for streams. Thereby, you can directly "send" the object contents to a stream (without the need to store everything in an intermediate string object). And you can use the same code to populate a string to be returned by a toStringmethod, too:
struct Student {
std::string name;
int age;
double finalGrade;
std::string toString() const;
};
ostream& operator << (ostream &os, const Student &s) {
return (os << "Name: " << s.name << "\n Age: " << s.age << "\n Final Grade: " << s.finalGrade << std::endl);
}
std::string Student::toString() const {
stringstream ss;
ss << (*this);
return ss.str();
}
int main() {
Student stud { "john baker", 25, 1.2 };
std::cout << "stud directly: " << stud << endl;
std::string studStr = stud.toString();
std::cout << "stud toString:" << studStr << endl;
}
You can't add anything you want to a std::string like you can to a Java String. Notably, most objects are not expected to have a toString member function. However, the standard library provides std::to_string which allow you to convert numeric values to an std::string. For example you could wrap the numeric values with a std::to_string to fix your function :
#include <string>
struct Student {
std::string name;
int age;
double finalGrade;
std::string toString() {
return "Name: " +
name +
"\n Age: " +
std::to_string(age) +
"\n Final Grade: " +
std::to_string(finalGrade);
}
};
Edit : Though this answer explains why what you tried doesn't work, the other answer's solution is the preferred approach.
You cant add int to std::string because the std::string operator+ was not overloaded to int.
The best solution is to use string stream :
#include <sstream>
std::string toString() {
std::ostringstream strout;
strout<< "Name: " << name << "\n Age: " << age << "\n Final Grade: " << finalGrade;
return strout.str();
}
You cannot just add an int or a double to an std::string. Use std::to_string to convert them first. This should work fine:
std::string toString() {
return "Name: " + name + "\n Age: " + std::to_string(age) + "\n Final Grade: " + std::to_string(finalGrade);
}