Reputation: 231
I have a program that displays a menu. The menu contains both an array of items (strings), and prices (double type values). The program serves no further purpose but to display a menu.
Of course, by default the double type values are displayed with decimals. This is useful in this case because we are listing the prices of items; however, usually prices initially begin with a dollar sign ($). To my knowledge, the iomanip header contains the "put_money" & "put_money" functions, but these do not do what I need them to do. What I need is for each price within to menu to be displayed with a dollar sign alongside the actual value. For example:
My desired output is this:
Please select an item to purchase:
______________________________________________________
Item: Prices: Item: Prices: Item: Prices:
______________________________________________________
Water $100 Milk $200 Juice $300
Wine $400 Bread $500 Apple $600
Tuna $700 Steak $800 Bandage $900
Med-Kit $1000 Splint $1100 Thread $1200
My current program produces this:
Please select an item to purchase:
______________________________________________________
Item: Prices: Item: Prices: Item: Prices:
______________________________________________________
Water 100 Milk 200 Juice 300
Wine 400 Bread 500 Apple 600
Tuna 700 Steak 800 Bandage 900
Med-Kit 1000 Splint 1100 Thread 1200
Is there a more efficient way to add the dollar sign to all my values without having to manually add each individual dollar sign? I just felt manually adding them could be tedious in a large project (certainly not like this, but possibly similar).
#include <iostream>
#include <iomanip>
#include <string>
int main(void) {
unsigned short int width = 10;
unsigned short int prec = 6;
float prices[12] = {100.00, 200.00, 300.00, 400.00, 500.00, 600.00, 700.00, 800.00, 900.00, 1000.00, 1100.00, 1200.00};
std::string items[12] = {"Water", "Milk", "Juice", "Wine", "Bread", "Apple", "Tuna", "Steak", "Bandage", "Med-Kit", "Splint","Thread"};
std::cout << "\nPlease select an item to purchase:\n\n";
std::cout << "_________________________________________________________________\n\n";
std::cout << std::setw(width) << "Item:" << std::setw(width) << "Prices:" <<std::setw(width) << "Item:" <<std::setw(width) << "Prices;" <<std::setw(width) << "Item:" <<std::setw(width) << "Prices:" << "\n";
std::cout << "_________________________________________________________________\n\n";
std::cout << std::setw(width) <<items[0] <<std::setw(width) << prices[0] <<std::setw(width) << items[1] <<std::setw(width) << prices[1] <<std::setw(width) << items[2] <<std::setw(width) << prices[2] << "\n";
std::cout << std::setw(width) <<items[3] <<std::setw(width) << prices[3] <<std::setw(width) << items[4] <<std::setw(width) << prices[4] <<std::setw(width) << items[5] <<std::setw(width) << prices[5] << "\n";
std::cout << std::setw(width) <<items[6] <<std::setw(width) << prices[6] <<std::setw(width) << items[7] <<std::setw(width) << prices[7] <<std::setw(width) << items[8] <<std::setw(width) << prices[8] << "\n";
std::cout << std::setw(width) <<items[9] <<std::setw(width) << prices[9] <<std::setw(width) << items[10] <<std::setw(width) << prices[10] <<std::setw(width) << items[11] <<std::setw(width) << prices[11] << "\n";
std::cin.get();
std::cin.get();
return 0;
}
Please excuse the excessive length of the code. Thanks to everyone in advance for helping.
Upvotes: 0
Views: 2097
Reputation: 490098
Actually std::put_money
can and will do exactly what you're asking if you use it correctly.
There are two parts to that. First of all, you have to select a locale. The default "C" locale simply doesn't define a currency symbol to use. Typically you'll want to use the nameless locale, something like this:
std::cout.imbue(std::locale(""));
This chooses (and uses) the locale for which the user has configured their environment, so (for example) a typical US user will get some US English locale with a dollar sign as the currency symbol, but a typical German user will get a German locale with a euro sign as the currency symbol1. This will also affect the formatting of the numbers. The example output below shows it using a comma as a thousands separator and a period (full-stop) as a decimal separator. Users in many European countries (for one example) should expect those two to be reversed.
Then you need to set the showbase
flag for the stream. For other numbers, this tells the stream to show the base of the number as converted, so (for example) if you print out something in hexadecimal, it'll be preceded by a 0x
(or 0X
). When you write money, that gets re-purposed to saying whether to show the currency symbol or not.
You normally want to combine that with the advice you've already received about creating a class (or struct) to store the data about an item. Rather than a function named display
, I'd create an overload of operator<<
to display an item though.
Note that money values are stored as long double
s. In a typical case, it will be stored as an integral number of the smallest denomination of currency in normal use (e.g., in the US, an integral number of pennies). Therefore, initialization to 100.0
would actually mean a value of $1.00
2.
With that (and leaving out the code for your header), creating and displaying the table might look something like this:
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
unsigned short int width=10;
unsigned short int prec=6;
class item {
std::string name;
long double price;
public:
item(std::string const &name, double price): name(name), price(price) {}
friend std::ostream &operator<<(std::ostream &os, item const &i) {
return os<<std::setw(width) << i.name
<<std::setw(width) << std::showbase << std::put_money(i.price);
}
};
int main(void) {
std::vector<item> items {
{"water", 10000},
{"Milk", 20000},
{"Juice", 30000},
{"Wine", 40000},
{"Bread", 60000},
{"Apple", 70000},
{"Tuna", 80000},
{"Steak", 90000},
{"Bandage", 100000},
{"Med-Kit", 110000},
{"Splint", 120000},
{"Thread", 130000}
};
std::cout.imbue(std::locale(""));
unsigned count=0;
for (auto &&item:items) {
std::cout<<item;
if (++count==3) {
std::cout<<"\n";
count=0;
}
}
}
Result:
water $100.00 Milk $200.00 Juice $300.00
Wine $400.00 Bread $600.00 Apple $700.00
Tuna $800.00 Steak $900.00 Bandage $1,000.00
Med-Kit $1,100.00 Splint $1,200.00 Thread $1,300.00
If you decide to do the formatting on your own, be aware that it won't be quite as simple as just inserting a $
before the item to be written. The problem is that you pretty much need to explicitly set a width and precision when you write out the value. When you do that, you'll quickly find that the $
gets inserted before the padding for the number, so (for example) your first entry will end up looking something like this:
water$ 100.00
...instead of putting the currency symbol next to the number where you almost certainly want it. It is possible to prevent that with enough extra work:
std::ostringstream temp;
temp << '$' << std::setprecision(your_precision) << value;
std::cout << std::setw(your_width) << temp.str();
Although it may be open to argument that usingstd::put_money
is a little more work than you'd like, by the time you get the formatting even reasonably close to correct on your own, it's quite a bit more work still (and adding even minimal support for internationalization is quite a bit more work again).
get_money
and put_money
are symmetrical, so if a user enters $100.00
and you read it with get_money
, store whatever that produces, and then write it back out with put_money
, you should get $100.00
as the result.Upvotes: 3
Reputation: 7197
Why don't you create a class
to store the items?
For example, you can have:
class Item
{
private:
double price;
string item;
public:
void display()
{
cout << "$" << price;
}
};
So you call the display
function to display the price in monetary value.
Upvotes: 4