I started reading C++ Primer, 5th Edition and I'm having troubles understanding one thing when it comes to std::cin.
The following is the code they present as their example. The idea behind it is that a bookstore is recording its transactions and the program should be able to sum back-to-back transactions as long as they belong to the same book (ie, they have the same isbn).
I haven't included the header file since I believe it isn't relevant to my question. In case it's actually needed, you can find it here.
My issue with the example is that the comments explaining the code say that the first Sales_item object, named total, is used to store the current transaction, while the one named trans is used to 'hold the running sum'. That is, the total.
#include <iostream>
#include "Sales_item.h"
int main()
{
Sales_item total; // variable to hold data for the next transaction
// read the first transaction and ensure that there are data to process
if (std::cin >> total) {
Sales_item trans; // variable to hold the running sum
// read and process the remaining transactions
while (std::cin >> trans) {
// if we're still processing the same book
if (total.isbn() == trans.isbn())
total += trans; // update the running total
else {
// print results for the previous book
std::cout << total << std::endl;
total = trans; // total now refers to the next book
}
}
std::cout << total << std::endl; // print the last transaction
} else {
// no input! warn the user
std::cerr << "No data?!" << std::endl;
return -1; // indicate failure
}
return 0;
}
I've seen various examples with this kind of reasoning, and to me it looks counterintuitive. Shouldn't the first variable be holding the total (since it belongs to a wider scope and it's named, you know, total) while the second holds the current transaction? Did I understand this completely backwards and the second cin is actually holding the total?
I agree, the comments appear to be swapped. They should be:
Sales_item total; // variable to hold the running sum
Sales_item trans; // variable to hold data for the next transaction
I am supposed to use a parallel array to show how much a cup of coffee is based on what add-in is added. The original cup of coffee is 2 dollars. I am mostly confused with how to output the correct results. Currently, it will output saying "Order total is2". What am I missing?
// JumpinJava.cpp - This program looks up and prints the names and prices of coffee orders.
// Input: Interactive
// Output: Name and price of coffee orders or error message if add-in is not found
#include <iostream>
#include <string>
using namespace std;
int main()
{
// Declare variables.
string addIn; // Add-in ordered
const int NUM_ITEMS = 5; // Named constant
// Initialized array of add-ins
string addIns[] = {"Cream", "Cinnamon", "Chocolate", "Amaretto", "Whiskey"};
// Initialized array of add-in prices
double addInPrices[] = {.89, .25, .59, 1.50, 1.75};
bool foundIt = false; // Flag variable
int x; // Loop control variable
double orderTotal = 2.00; // All orders start with a 2.00 charge
// Get user input
cout << "Enter coffee add-in or XXX to quit: ";
cin >> addIn;
// Write the rest of the program here.
for(int i = 0; i < NUM_ITEMS; i++){
if (addIns[i] == (addIn))
foundIt = true;
if (foundIt)
{
x = orderTotal + addInPrices[i];
cout << "Order Total is" << x << endl;
}
else cout <<"Sorry, we do not carry that."<< endl;
}
return 0;
} // End of main()
In this line:
x = orderTotal + addInPrices[i];
you are setting x (an int value) to something like 2.00 + 0.25, right? Your compiler is likely warning you about a possible loss of precision here. An integer value can only contain whole numbers: 1, 2, 3, etc. If you try to set it to a floating point number like 2.25, it will be truncated (the decimal points chopped off) leaving only the integer part. So the result of x = 2.25 will be the value 2 in x, which is consistent with your output.
In your assignment template, your instructor has written this comment next to the declaration of x:
int x; // Loop control variable
It seems clear to me that the intent was for x to be what you put in the for loop, i.e. the variable controlling how many loops happen and when it ends. You are choosing to create a new variable i instead. This would also explain why x is not initialized to anything - the initialization would happen in the for-loop if you did it the intended way.
Try this: Instead of using x to store the new price, simply add the add-in price to orderTotal, so that it's always up-to-date and has the correct value. This way you do not need to use x for this at all, and can use it in the for-loop instead. You would then be printing orderTotal instead of x in your output.
The problem: So earlier the requirement for this C++ program was to just deal with one file's input (Each line represents the average of 10 minutes of the weather detail, about 50k lines). The end user wanted to be able to find out the average of the weather attributes for: a) A specified month and year, b)Average for each month of a specified year, c) Total for each month of a specified year, and d) average of each month of a specified year outputted to a .csv file.
Example: (First 4 lines of input csv)
WAST,DP,Dta,Dts,EV,QFE,QFF,QNH,RF,RH,S,SR,ST1,ST2,ST3,ST4,Sx,T
1/01/2010 9:00,8,151,23,0.1,1014.6,1018.1,1018.2,0,43.3,7,813,23.6,27,26.9,25.4,10,20.98
1/01/2010 9:10,8.7,161,28,0.1,1014.6,1018.1,1018.2,0,44.4,6,845,23.7,26.9,26.9,25.4,10,21.37
1/01/2010 9:20,8.9,176,21,0.2,1014.6,1018.1,1018.2,0,43.4,6,877,23.8,26.9,26.9,25.4,9,21.96
Solution: As not all the data from each line was required, upon reading in each line, they're parsed, segregated and built into an object instance of 'Weather', which consists of:
Date m_dateObj;
Time m_timeObj;
float m_windSpeed;
float m_solarRadiation;
float m_airTemperature;
A vector of Weather object was made to host this information.
Now, the problem has expanded to multiple files (150K-500K lines of data). Reading in multiple files is fine, all the data is retrieved and converted to Weather object with no problems, I'm just having trouble with the design(more specifically the syntax aspect of it, I know what I want to do). Additionally, there is a new option introduced where the user will enter dd/mm/yy and instances of highest solarRadiation for that day will be outputted(This requires me to have access to each specific object of weather and I cant just store aggregates).
BST and Maps are mandatory, so what I thought was: Data is read in line by line, for each line - Convert into Weather obj, store into a vector specifically for that month+year, so for every month of every year there will be a different vector eg; jan2007, feb2007, jan2008 etc. and each of these vectors are stored in a map:
map<pair<int, int>, vector<Weather> > monthMap;
So it looks like
<pair<3,2007>, march2007Vec>
and stores these maps into the BST (which I would need to randomize since its sorted data, to avoid making my BST a linked list, tips on how to do it? I found snippets for self-balancing trees that I might implement). This should work as the key for all maps are unique, thus making all BST nodes unique.
So it would look like this -
User runs program
Program opens files (there is a txt file with file names in it)
For each file
Open file
For each line
Convert into weather Object
Check month+year,
if map for combination exists,
add to that vector (eg march2007)
else
create new vector store in new map
Close file
add all maps to BST
BST will self sort
Provide user with menu to choose from
The actual computation of what the user needs is pretty simple, I just need help figuring out how to actually make it so there are n numbers of maps and vectors (n = number of maps = number of vectors, I think), as I don't know how many months/years there will be.
Heres a snippet of my code to get a better understanding of what I'm trying to do:
int main()
{
vector<Weather> monthVec;
map<pair<int, int>, vector<Weather> > monthMap;
map<pair<int, int>, vector<Weather> >::iterator itr;
int count = 0;
bool found = false;
Weather weatherObj;
ifstream weatherFileList;
weatherFileList.open("data/met_index.txt");
if(weatherFileList.is_open())
{
cout << "Success";
while (!weatherFileList.eof())
{
string data;
string fileName;
getline(weatherFileList, fileName);
cout << fileName << endl;
fileName = "data/" + fileName;
cout << fileName << endl;
ifstream weatherFile;
weatherFile.open(fileName.c_str());
getline(weatherFile, data);
while (!weatherFile.eof())
{
getline(weatherFile, data);
if (!data.empty())
{
weatherObj = ConvertData(data);
//cout << count << " " << weatherObj.GetTime().ToString() << endl;
//monthVec.push_back(weatherObj);
// for (itr = monthMap.begin(); itr != monthMap.end(); ++itr)
// {
//
// }
int month = weatherObj.GetDate().GetMonth();
int year = weatherObj.GetDate().GetYear();
itr = monthMap.find(make_pair(month,year));
if(itr != monthMap.end())
{
monthVec = itr->second;
monthVec.push_back(weatherObj);
}
else
{
}
count++;
}
//cout << data << endl;
}
weatherFile.close();
}
listOptions();
}
else
{
cout << "Not open";
}
cout << count << endl;
cout << monthVec.size() << "/" << monthVec.capacity();
return 0;
}
Apologies for the untidy code, so I was thinking about how to make it so for every new combination there's a new vector placed in a new map, but because of my inexperience, I don't know how to syntax it or even search it well.
TLDR: Need to map unknown number of combinations of ,VectorOfObject>
Would one make a switch case and have 12 vectors, one for each month hardcoded and just store all February (2007 2008 2009 etc) details in it, that would mean a lot of unnecessary processing.
How would one create different vectors without actually giving them a unique name for reference in the code, (<3,2007>,March2007)
How would one retrieve the contents of the vector(Of which we don't know the name, sure we know the key is 03 2007 aka march 2007, but wouldn't we need an explicit name to open the vector? march2007.find()), which is inside a map.
Thanks for the read, and potential help!
Please do Direct Message me if you'd like to see the problem in more detail, I would be grateful!
I have a class with which I can create a number of objects.
class Employee{
public:
string firstName;
string lastName;
string gender;//gender - if necesary
string identificationCode;//an Id for every employee
string typeOfEmployee;//is Programmer, is Tester and so on...
string getFirstName(){ return this->firstName; } //show the name
string getLastName(){ return this->lastName; }//show the name
string getGender(){ return this->gender; }//show the gender - if necesary
string getID(){ return this->identificationCode; }//show ID
string getTypeOfEmployee(){ return this->typeOfEmployee; }//show type of job
};
class Programmer : public Employee{
public:
vector<string> knownLanguages;//array of known programming languages
unsigned int countProgrammers;
}programmer[5];
Programmer::Programmer()
{
countProgrammers++;
}
int main(){...
switch (checkJob(getTokens[3]))
{
case 1:
Programmer programmer[counter];//this is error = expression must be a value
programmer[counter].identificationCode = getTokens[0];
programmer[counter].firstName = getTokens[1];
programmer[counter].lastName = getTokens[2];
programmer[counter].typeOfEmployee = getTokens[3];
programmer[counter].knownLanguagessplitString(getTokens[4], SecondDelimiter);
//cout << programmer[counter].firstName<<" " << programmer[counter].lastName<<" with ID: " << programmer[counter].identificationCode<<" is a "<<programmer[counter].typeOfEmployee<<" and knows " << endl;
counter++;
break;
...}
And I'll want to use a counter, that, when a new object is being created, or when I'm using a flow control structure to add more details to an object, whatsoever, I want to increment it.
My preference is that I want to keep it inside the class.
So far I've defined countProgrammers, but because I'm using programmer[1] and so on, it would be a different value for each Programmer I create.
Is there a way I keep the variable inside the class, but actively show me the number of total objects I create, if I'll call it like
cout<<programmer.countProgrammers; (this is not right because of the way I've defined the class, the correct way should be cout<<programmer[1].countProgrammers;, but it will show a different value for wach object created, for example, for third object it will be 3 and so on)//resolved
You would have to declare the variable as static
static unsigned int countProgrammers;
Then in the body of your constructor
Programmer::Programmer()
{
++countProgrammers;
}
That way every time a Programmer is constructed that variable will increment.
To print this value you would say
std::cout << Programmer::countProgrammers << std::endl;
At the moment I am using a vector to store pointers to the object every time one is made, but that feels a little silly. There's probably a better way, but I haven't found it.
What I'm doing: Example usage:
The problem:
If I want to retrieve a certain Date I have to go over all items in the vector to see if RecPaymentsStack.stackDate matches the date the user requested.
The RecPaymentStack is actually completely useless at the moment because what I should be doing, is, when adding a new item, checking if a "RecPaymentStack.stackDate" has already been made for the new item's Date property, and if so add the new pointer to "RecPayments" to an array of pointers inside the "RecPaymentStack" object. But how?
I'm probably unnecessarily complicating things (something I do a lot) so an explenation on how something like this should be done would be very nice.
Detailed info: (in case I was being too vague)
The below example is supposed to resemble a calendar that can hold certain items (RecPayments) and those items are grouped by their date (RecPaymentsStack).
struct RecPayments
{
std::string name;
Date* date;
float cost;
};
struct RecPaymentsStack
{
Date* stackDate; //This stack's date
RecPayments * thePaymentItem; //Hold pointer to the actual item
};
And here's how I'm currently storing them
std::vector<RecPaymentsStack*> RecPaymentsVector; //This vector will hold pointers to all the Recurring Payments
void addRecurring(std::string theDate,std::string theName,float theCost)
{
//New recurring payment
RecPayments * newPaymentItem = new RecPayments;
//Set recurring payment properties
newPaymentItem->name = theName;
newPaymentItem->date = new Date(stringToChar(theDate));
newPaymentItem->cost = theCost;
//Add recurring payment to stack
RecPaymentsStack * addToStack = new RecPaymentsStack;
addToStack->stackDate = new Date(stringToChar(theDate));
addToStack->thePaymentItem = newPaymentItem;
//Add pointer to RecPaymentsStack to vector
RecPaymentsVector.push_back(addToStack);
}
So to retrieve the items for a given date, I am currently going over all pointers in the vector to see if the "stackDate" property matches the requested date, and if so I use the "thePaymentItem" property to show the actual item.
void getItemsNow(Date requestedDate)
{
std::cout << "Showing Dates for " << requestedDate << std::endl;
unsigned int i;
for(i=0;i<RecPaymentsVector.size();i++) //Go over all items in vector
{
Date dateInVector(*RecPaymentsVector[i]->stackDate); //Get the date from the vector
if(dateInVector == requestedDate) //See if Date matches what the user requested
{
//Date matched, show user the item properties.
std::cout << "Date: " << dateInVector <<
" has name: " << RecPaymentsVector[i]->thePaymentItem->name <<
" and price " << RecPaymentsVector[i]->thePaymentItem->cost <<
std::endl;
}
}
}
3 problems with this:
Going over all items in the vector is highly inefficient if I only
need a couple of pointers
The RecPaymentStack is actually completely useless at the moment because what I should be doing, is, when adding a new item, checking if a "RecPaymentStack.stackDate" has already been made for the new item's Date property, and if so add the new pointer to "RecPayments" to an array of pointers inside the "RecPaymentStack" object. But how?
All of this feels extremely silly to begin with.. there's probably a much easier/professional way to do this but I can't find out what, probably because I'm still thinking like a PHPer.
So the general idea here is that I end up doing something like (silly example)
for each RecPaymentsStack->stackDate //For each unique Date, show it's children items.
{
cout << "The Date is " CurrentRecPaymentsStack->stackDate and it holds the following items:
for each CurrentRecPaymentsStack->thePaymentItem //This would now be an array of pointers
{
cout << "item name " CurrentRecPaymentsStack->thePaymentItem->name << " with cost " << CurrentRecPaymentsStack->thePaymentItem->cost << endl;
}
}
Which would basically go over all the unique "RecPaymentsStack" objects (unique determined by it's "Date" property) and for each Date it would then show it's "children" from the RecPayments struct.
And there has to be some way to search for a particular date without having to go over all the available ones.
Rather than using a vector to manage your items, you should replace your RecPaymentsStack instance with a std::multimap. The key type is your Date structure, the value type is RecPayments (which I would change to the singular form RecPayment). Small example (untested):
typedef std::multimap<Date, RecPayment> RecPaymentsByDateMap;
typedef std::pair<RecPaymentsByDateMap::iterator,
RecPaymentsByDateMap::iterator>
RecPaymentsByDateMapIters;
RecPaymentsByDateMap payments_by_date;
RecPaymentsByDateMapIters findByDate(Date date) {
return payments_by_date.equal_range(date);
}
...
// find all payments with the given date
RecPaymentsByDateMapIters iters = findByDate(...);
for (RecPaymentsByDateMap::iterator it = iters.first;
it != iters.second;
++it)
{
std::cout << "Payment " << it->second.name << std::endl;
}
I might design it like this -- this is just a loose idea, details should be adjusted according to your requirements:
#include <deque>
#include <map>
#include <string>
struct RecPayment
{
std::string name;
Date date;
float cost;
};
struct RecPaymentsStack
{
Date stackDate;
std::deque<RecPayment> thePaymentItem;
bool operator<(RecPaymentsStack const & rhs) const
{
return stackDate < rhs.stackDate;
}
explicit RecPaymentsStack(Date const & d) : stackDate(d) { }
};
typedef std::multimap<RecPaymentsStack> PaymentsCollection;
Now you can insert elements:
PaymentsCollection payments;
{
auto it = payments.emplace(Date("..."));
it->thePaymentItem.emplace_back(Payment{name1, date1, cost1});
it->thePaymentItem.emplace_back(Payment{name2, date2, cost2});
it->thePaymentItem.emplace_back(Payment{name3, date3, cost3});
}