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 encountered a strange problem, at times, at no. When I read data from a file to insert into the map, data read from file be attached to a struct type is TradeRecord and then insert to map. But when I init object order_tmp I don't assign value 0 to it so have some field in TradeRecord don't have in the file be assign junk value from c++ compiler.
//struct TradeRecord
struct TradeRecord
{
int order; // order ticket
int login; // owner's login
char symbol[12]; // security
int digits; // security precision
int cmd; // trade command
int volume; // volume
//---
__time32_t open_time; // open time
int state; // reserved
double open_price; // open price
double sl,tp; // stop loss & take profit
__time32_t close_time; // close time
int gw_volume; // gateway order volume
__time32_t expiration; // pending order's expiration time
char reason; // trade reason
char conv_reserv[3]; // reserved fields
double conv_rates[2]; // convertation rates from profit currency to group deposit currency
// (first element-for open time, second element-for close time)
double commission; // commission
double commission_agent; // agent commission
double storage; // order swaps
double close_price; // close price
double profit; // profit
double taxes; // taxes
int magic; // special value used by client experts
char comment[32]; // comment
int gw_order; // gateway order ticket
int activation; // used by MT Manager
short gw_open_price; // gateway order price deviation (pips) from order open price
short gw_close_price; // gateway order price deviation (pips) from order close price
double margin_rate; // margin convertation rate (rate of convertation from margin currency to deposit one)
__time32_t timestamp; // timestamp
int api_data[4]; // for api usage
TradeRecord *__ptr32 next; // internal data
};
//code read data from file
while (file.good())
{
std::getline(file, line_str);
boost::split(fields, line_str, boost::is_any_of(k_delimiter));
// line don't enough data
if (fields.size() < k_line_fields)
{
LOG(DEBUG) << m_log_tag << "Ignore line " << line << ", not enough data: " << line_str;
line++;
continue;
}
LOG(DEBUG) << m_log_tag << "Data line " << line << ": " << line_str;
TradeRecord order_tmp;
order_tmp.login = atoi(fields[0].c_str());
order_tmp.order = atoi(fields[1].c_str());
strncpy_s(order_tmp.symbol, _countof(order_tmp.symbol), fields[2].c_str(), _TRUNCATE);
order_tmp.volume = atoi(fields[3].c_str());
order_tmp.cmd = atoi(fields[4].c_str());
order_tmp.open_price = atof(fields[5].c_str());
order_tmp.margin_rate = atof(fields[6].c_str());
order_tmp.open_time = atoi(fields[7].c_str());
list_open_order.insert(std::make_pair(order_tmp.order, order_tmp));
LOG(DEBUG) << std::fixed << "for test, read open order: " << order_tmp.order << ", swap=" << order_tmp.storage;
line++;
}
Like you can see, in TradeRecord has so many fields but in my file not enough, so c++ auto assign value for these(-92559631349317830000000000000000000000000000000000000000000000.000000 something like this)
But I do not understand why this problem is when not because sometimes it is normal
You should not use a variable without giving it a default value.
In C++ (unlike some other programming languages like Java) do not auto-initialize variables. So in your case, the integer will be in the stack with the value of whatever random data that was there.
I don't really understand your question, but when the compiler gives your variable a random number like 9255698272838000000, it's because you either didn't give this variable an initial value or assigned it to another variable that you didn't give an initial value.
By default, the compiler just allocates memory for the struct's members (or for any variable you create). It does not assign a value to them until you explicitly tell it to do so. For example,
int i;
allocates an integer but does not give it a value. Because your computer's memory is constantly being passed around (but not zeroed-out) as programs execute and terminate by the operating system, the variable can contain literally any value before you assign it one. It is simply a region of memory, and it will probably contain whatever value it had when it was last used by a (different) program.
The following code:
int i = 0;
will allocate a variable and assign it a value.
If you initialize your struct like so:
traderecord order_temp = {};
the compiler will automatically zero-out your structure so all of its members are equal to zero. Then you can simply assign values to each member as it becomes necessary.
I think I'm just confused on the wording to this project, but I'm posting here to make sure I have the basics on classes correct (like I said, we just started learning them).
The beginning of the project prompt is as follows:
Declare and define a class called Odometer. This class will have two private variables, one for the miles driven and the other for the gallons of gas pumped into the car.
The member functions should include:
A constructor that takes initial values for both of the private variables.
A default constructor that sets both values to zero.
Along with more member functions that aren't important for my problem. I understand the default constructor fully, but the other is the one I'm having troubles with. If he (my professor) wants us to gather initial variables, then why would it need any parameters at all? I guess I could pass an empty string into it as a parameter, but I feel like there's something I'm missing here...
To expand on the point of this project, in case it's needed, we are creating a program that allows the user to continually enter (on a menu screen) either miles driven or gallons put into their tank. The program will then find the mpg, when the user requests it. Very simple.
Here's part of the program, which should be enough for someone to help me with this. The second/non-default constructor seems like it would work, except obviously I need some type of parameter. Any suggestions or help is greatly appreciated.
#include <iostream>
using namespace std;
class Odometer{
public:
Odometer(); // sets values to 0
Odometer(WHAT GOES HERE); // gathers initial values
void get_miles();
void get_gallons();
void add_in_trip_miles();
void add_gas();
private:
double milesDriven; // represents the miles the car has driven
double gallonsGas; // represents the number of gallons pumped into car
};
int main() {
Odometer userInfo; // creates object for the user-inputted values
bool quit = false; // true when user wants to quit
int userChoice; // for navigating the menu screen
while(!quit){
cout << "To view total miles, enter 1. To view total gallons, enter 2.\nTo record more miles driven, enter 3. To record gallons pumped into the tank, enter 4.\n To view the average MPG, enter 5. To reset the odometer, enter 6.\n To quit the program, enter 7." << endl;
cin >> userChoice;
if(userChoice == 1) userInfo.get_miles(); // TODO: switch/case statement instead?
if(userChoice == 2) userInfo.get_gallons();
if(userChoice == 3) userInfo.add_in_trip_miles(); // TODO: "function which increases the miles by the amount sent in its parameter
}
cout << "Have a nice day!" <<endl;
return 0;
}
Odometer::Odometer(){ // sets values to 0 (default)
milesDriven = 0;
gallonsGas = 0;
}
Odometer::Odometer(WHAT GOES HERE?){ // gathers initial values
cout << "Please enter an initial value for miles driven." << endl;
cin >> milesDriven;
cout << "Please enter an initial value for how many gallons were put into the car." << endl;
cin >> gallonsGas;
}
Your teacher is asking you to implement the second constructor with parameters so user will be able to initialize the object with the state he wants. I would implement it like this:
Odometer(double milesDriven_, double gallonsGas_) :
milesDriven(milesDriven_),
gallonsGas(gallonsGas_)
{}
Here's the code assignment.
A bank charges $10 per month plus the following check fees for a commercial checking account:
$0.10 each for fewer than 20 checks
$0.08 each for 20-39 checks
$0.06 each for 40-59 checks
$0.04 each for 60 or more checks
The bank also charges an extra $15.00 if the balance of the account falls below $400 (before any check fees are applied). Write a program named lab2 that inputs for the beginning balance and the number of check written from the transaction file. Compute and display the bank's service fees for the month.
Input Validation: Do not accept a negative value for the number of checks written. If a negative value is given for the beginning balance, display an urgent message indicating the account is overdrawn.
The program should have a loop execution of six times for reading data from a file named transaction.txt.
Click the link transaction.txt download the file and store it in folder c:\cis180\lab2. The file transaction.txt contains the beginning balance and number of checks written for six transactions.
Here is the content of the file.
The text file
-100.00 -beginningbalance
30 - number of checks
400.00
-20
300.00
36
300.00
47
350.00
5
300.00
70
My code
#include <iostream>
#include <fstream>
#include <string>
#include <stdlib.h>
#include <sstream>
//include a library file to input data from file
using namespace std;
bool isNumeric(string pszInput);
int main()
{//start
// Constants
int numChecks; // Number of checks written for the month
double acctBalance; // Account balance before subtracting check fees
double checkFee; // Fee based on number of checks written
double totalFees; // Total monthly bank fees
ifstream inputFile;
//Open the file
inputFile.open("c:\\cis180\\transaction.txt");
//Initialize month counter
int transaction = 0; //first month
//Create a loop to execute 6 times. Each time the loop body reads the beginning balance and number of checks for six transaction, calculate the bank fees, display the beginning balance, number of checks, and the bank fees.
inputFile >> acctBalance;
// Display the beginning balance
if (acctBalance>0)
{
cout<<"Your beginning balance is: "acctBalance << endl;
}
else (acctBalance<0)
{
cout<<"Your account is overdrawn!" << endl;
}
// Display the number of checks that were written.
if (numChecks>0)
{
cout<<"The number of checks written were: "numChecks<<endl;
}
else (numChecks<0)
{
cout<<"Number of checks must be 0 or more."<<endl;
}
// Determine whether the account is overdrawn.
// Validate number of checks written.
// If the number of checks is less than 0
{ // numChecks is valid, so we can calulate the fees.
// Calculate checkFee - Use if/else if structure
const double MONTHLY_FEE= 10.00; // Base monthly fee
const double MIN_BAL= 400.00; // minimum balance
const double LOW_BAL_FEE= 15.00; // extra fee for low balance
for (int transaction = 0; transaction <=6; transaction++);
if (numChecks<20)
{
checkFee=(0.1*numChecks)+MONTHLY_FEE<<endl;
}
else if (numChecks<40 )
{
checkFee=( 0.08*numChecks)+MONTHLY_FEE<<endl;
}
else if (numChecks<60 )
{
checkFee=( 0.06*numChecks)+MONTHLY_FEE<<endl;
}
else (numChecks>60 )
{
checkFee=( 0.04*numChecks)+MONTHLY_FEE<<endl;
}
// Calculate totalFees
if (numChecks<20 && acctBalance<MIN_BAL)
{
totalFees=checkFee+LOW_BAL_FEE<<endl;
}
else if (numChecks<40 && acctBalance<MIN_BAL)
{
totalFees=checkFee+LOW_BAL_FEE<<endl;
}
else if (numChecks<60 && acctBalance<MIN_BAL)
{
totalFees=checkFee+LOW_BAL_FEE<<endl;
}
else if (numChecks>60 && acctBalance<MIN_BAL)
{
totalFees=checkFee+LOW_BAL_FEE<<endl;
}
else (numChecks<20 && acctBalance>MIN_BAL)
{
totalFees=checkFee
}
// Display results: The bank fee
cout<<"The bank fee this month is "<<totalFees<<endl;
}//end the loop
return 0;
}//end
And the errors I'm getting when I try to compile.
Error E2379 lab3.cpp 33: Statement missing ; in function main()
Error E2379 lab3.cpp 36: Statement missing ; in function main()
Warning W8004 lab3.cpp 115: 'transaction' is assigned a value that is never used in function main()
So basically my only problem is already in the title. Can anyone help out? Also I'm new to the C++ language so please be gentle. And if there's any other problems can you point it out to me? Thanks in advance.
You forgot the operators here
cout << "Your beginning balance is: " << acctBalance << endl;
^^
and here
cout << "The number of checks written were: " << numChecks << endl;
^^
Why are you including stdlib.h? I don't see where you are you are using it. If you need this header I'd recommend cstdlib instead.
As already pointed out in the comments you also made a semicolon instead of { which appears a few lines before in your code. Please consider spacing out your operators like this:
if(numChecks < 20) {
}
Using a consistent indention style would also improve readability.
I am making fairly new to C++ and I am using it to make a text based game for a school project. However during the first section of the game the player answers questions by entering the number shown beside the answer they choose. However when I tested the variables the input going to using std::cout they return different values depending on where they are outputted. If I outputted them in the class I am using to set them (Introduction) the they return the correct value such as 1 or 3 etc. However when I output them in any file other than Introduction.cpp, the value displayed is -858993460 for all of the values. I get the same result from Main.cpp when I call them in my main function and if I call them from another function in a different class to Introduction.
This is an example of some of the code used to get input from the user:
void Introduction::CharacterCreation()
{
Universal universal;
std::fstream creation("Introduction_CharacterCreation.txt");
universal.line = 5;
for (int i = 0; i < universal.line; i++)
{
if (i > 0)
{
std::getline(creation, universal.displayText);
std::cout << universal.displayText << std::endl;
}
if (i == 4)
{
std::cout << std::endl;
std::cin >> universal.gender;
while (universal.gender <= 0 || universal.gender >= 3)
{
std::cout << "Please make a valid choice" << std::endl;
std::cin >> universal.gender;
}
}
}
// Code cut out here
}
The gender variable is an int declared in the Universal class, and the user is prompted to enter 1 for male or 2 for female by text pulled from a separate file. If the input is not 1 or 2 then a while loop forces the player to keep re-answering the question until they enter 1 or 2. The line variable is also an int however that is used for the for loops to ensure the right lines are read by the program.
To output the gender variable this is the code I use:
std::cout << gender << std::endl;
There is no universal. as it is being called within the Universal class itself.
This has confused me massively and I can't get my head around what is causing the problem. Any help or explanation would be great, thanks in advance.
Short answer: you're declaring a Universal object in your CharacterCreation() method. When this function exits since the scope of the universal variable was local so the entire object is destroyed.
Whatever you are outputting is just uninitialized garbage. It could really be any number depending on what system is compiling / running the program. To test this right after you input the gender, while still inside the function, try running
std::cout << universal.gender << std::endl;
This should output just fine.
There are a lot of ways you can go about fixing this. Since you didn't post where you call this method or your Universal class I can't say for sure. But I can speculate one such solution which is to declare the Universal object outside the method and then pass it in as a parameter:
Universal universal = Universal();
Introduction::CharacterCreation(universal);
std::cout << universal.gender << std::endl;
And just declare your function header to accept a Universal object:
void Introduction::CharacterCreation(Universal & universal)
{
//code here
}