cash reg loading individual words from each line into the different struct members - c++

I have this homework assignment that has me a little lost. I have been working on this assignment writing my code, erasing, rewrite, repeat etc. Here are the instructions:
Step (1)
Associated with this assignment is a data file called prices.txt. It contains details of the prices for items in a
grocery store. The first column is the barcode for the item (http://en.wikipedia.org/wiki/Barcode) the
second column, starting in position 11, is the product name, and the third column, starting in position 37 is
the product price.
Write a function with the signature int loadData() which prompts the user for the location of the data file
on disk and then loads the data from the file into an array of elements. Each element of the array should be
a struct declared as follows:
struct Item {
string code;
string name;
double price;
};
The array itself should be called items and should be declared at file scope as follows:
const int MAX_ITEMS = 100;
Item items[MAX_ITEMS];
Notice that the array has size 100, so you can assume the number of items in the data file is less than 100.
Therefore, when loadData has finished loading the data into the array some elements in the array will be unused. The function loadData returns the number of items actually loaded into the array.
I am unsure on how to attempt the function described in the instructions. My code:
int loadData () {
string inputFileName;
ifstream inputFile;
int numOfItems = 0;
cout << "Please input the name of the backup file: ";
cin >> inputFileName; //read user input for the location of the
//backup file
inputFile.open(inputFileName.c_str()); //open specified document
if (!inputFile.is_open()) { //If the file does not open the errormsg
cout << "Unable to open input file." << endl;
cout << "Press enter to continue...";
getline(cin, reply);
exit(1);
}
//Not sure where to start. I know I need to get each element from
//each newline.
return numOfItems;
}
I wanted to figure this out on my own but that isn't gonna happen. So if I could just get some hints or even suggested pools of knowledge that would guide me or even give me an idea of where to start.
addition: input file:
10001 Apples (bunch) 4.59
10002 Bananas (bunch) 4.99
10003 Pears (bunch) 5.49
20001 White bread (loaf) 2.69
20002 Brown bread (loaf) 2.89
20003 English Muffins (bag) 3.99
30001 Sugar (5 lb bag) 3.99
30002 Tea (box) 4.29
30003 Folger's Coffee (Can) 13.29
This is the entire input file.

Since the input file seems to be using fixed-width columns, it's actually very easy to extract the fields. Just read one line at a time, and for each line get each element as a sub-string, and put into the structure members. And there are functions to convert strings to floating-point values as well.
Don't worry about the possible leading or trailing spaces, there are ways of trimming that.

Related

How to split strings and pass them to class vectors from file

For my university class in programming we have been working on Object Oriented Programming (OOP) and are currently working on a group project. The project is to create a cash register that holds items with their names, amounts, and prices. As well as have a way to track the coins given by the user then determine the coin denomination. These are supposed to be done in different classes and involve objects.
My question is regarding the inventory manager that I am coding. The inventory manager is supposed to take the "data.txt" file and read it into the appropriate vectors. Currently I have a vector for the item name, price, amount, and then the itemList vector which holds a string of all 3 to print to the user for readability.
Here is a snippet from the data file:
20 1.99 Potato Chips
10 5.99 Ibuprofen
4 1.42 Candy
55 3.10 Coffee
12 3.25 Hummus
12 4.55 Guacamole
7 0.80 Baklava
45 1.50 Chocolate Chip Cookies
My question is, how do I split the line up so that I can pass the amount (first number) to the appropriate vector, pass the price to the appropriate vector, then pass the name to the appropriate vector. Essentially splitting each line into 3 parts. The part that is the most difficult to me is how the names of the items can be 1 word, 2 words, or even 3 words. Making it difficult to predict how many spaces the name will have, which caused a lot of my attempts to not work.
I found a working solution though I'm worried it's incorrect or inefficient and I'm curious in knowing the best way to do this. Thank you so much ahead of time and I will post the class definition and the method I'm working in down below.
< The stream object is inFile>
class inventoryManager
{
private:
double total, change, choice;
vector <int> amount;
vector <string> name;
vector <double> price;
vector <string> itemList;
public:
void fileOpen(fstream& inFile);
void fillInventory(fstream& inFile);
void printInventory(fstream& inFile);
};
void inventoryManager::fillInventory(fstream& inFile)
{
string temp;
string a, b;
while (!inFile.eof())
{
inFile >> a >> b;
amount.push_back(stoi(a));
price.push_back(stod(b));
getline(inFile, temp);
name.push_back(temp);
itemList.push_back(temp);
}
}
Attempted: I tried using the find() function to find each space then use the index to print the estimated indices to each side of the white space to the vectors. Though it was extremely messy and wouldn't work if a different data file was inputted. The idea of the program is to be able to work if a different file is put in, similar format but the amount could be 100, and prices could be more digits. I also tried editing the file directly by adding new lines for each space but ran into the item names with multiple spaces and ultimately didn't work.
You are trying to do too many new things at once. Break the problem into pieces and solve them separately, then combine them. To break the string into pieces you can use find and substr, you just have to be careful and debug until you're sure it's working perfectly:
string s = "45 1.50 Chocolate Chip Cookies";
cout << "s: " << s << endl; // for debugging
size_t first = s.find(' ');
cout << first << endl; // for debugging
string amountString = s.substr(0, first);
cout << amountString << "X" << endl; // for debugging
size_t second = s.find(' ', first+1);
cout << second << endl; // for debugging
string priceString = s.substr(first+1,second-first-1);
cout << priceString << "X" << endl; // for debugging
string nameString = s.substr(second+1);
cout << nameString << "X" << endl; // for debugging
The purpose of those X's is to be certain that the substring has no trailing space.
Once you have tackled the problem this way (and handed the result in for a grade), you can advance to tools like stringstream, and you won't have to deal with this grubby index arithmetic any more.

Store Input from Text File into Arrays or Variables?

My Problem:
I am very new to new to programming and trying to write a program in C++, I have a text file. *In the text file is stored is a Students Name, Grade, and Grade Letter. I want them stored as different types in arrays *
I want to store them individually in an array....
ie text file would look like this:
Jill Hamming A 96
Steven Jenning A 94
Tim Sutton B 89
Dillon Crass C 76
Sammy Salsa D 54
Karen Poulk D 49
I would like to store all the First names in one array, last names in another etc. So on and so on.
These arrays will later be assigned to object for the student. There maybe up to 500 students.
So the question:
How to store input from a text document into an array instead of using 500 variables.
ie. Here is my attempt.
int main()
{
/// the input is all different types, strings, ints and chars
string my_First_Name[500], my_Last_Name[500];
int my_grade[500];
char my_letter[500];
ifstream myfile("input.txt");
if (myfile.is_open()){
for (int i = 0; i < 500; i++) {
myfile >> my_First_Name[i] >> my_Last_Name[i] >> my_grade[i] >> my_letter[i];
}
// much later and irrelevent part but just showing because this is what I want to do. where Student Class exsists somewhere else. yet to be programmed.
Student myStudent [500];
myStudent[i].Grades = my_grade[i];
myStudent[i].LetterGrade = my_letter[i];
}
myfile.close();
//Exit
system("pause");
return 0;
}
When I went to print out what I had. I had all negative and weird numbers which means it was not initialized. Where did I go wrong?
When you have multiple arrays of the same size, it is usually as sign of poor design.
The rule of thumb is to have a record (or line of data) represented by a class or structure:
struct Record
{
string first_name;
string last_name;
int grade_value; // Can this go negative?
string grade_text;
};
If you know you are going to have 500, you can create an array for the data:
#define ARRAY_CAPACITY (500)
Record grades[ARRAY_CAPACITY];
This not a great solution, because you waste space if there are less than 500 and perform buffer overrun if you read more than 500.
Thus a better solution is to use std::vector, which allows you to append records as you read them. The std::vector will expand as necessary to contain the records. With an array, you would have to allocate a new array, copy old records to new array, then delete the old array.
Also, a good solution will include methods, inside Record, to read the data members from an input stream. Research "overloading stream extraction operator".
You input loop should look something like:
Record r;
while (input_file >> r)
{
student_grades.push_back(r);
}
You can find this information by searching stackoverflow. A good beginning search is "stackoverflow c++ read file space separated" or "comma separated" or "stackoverflow c++ read file structure".
Reading a record
You could expand the loop to something like this:
std::vector<Record> student_grades;
Record r;
while (input >> r.first_name >> r.last_name >> r.grade_value >> r.grade_text)
{
student_grades.push_back(r);
}
If you are allergic or limited to arrays, you will need to use a counter with the array.
#define MAXIMUM_RECORDS (500)
Record r;
Record grade_book[MAXIMUM_RECORDS];
unsigned int record_count = 0U;
while (input >> r.first_name >> r.last_name >> r.grade_value >> r.grade_text)
{
grade_book[record_count] = r;
++record_count;
if (record_count >= MAXIMUM_RECORDS)
{
break;
}
}
A for loop is not used because we don't know how many records are in the file, only a maximum that the program will read. If the file has 600 records, only 500 will be read.

update records in file (c++)

I wanted to ask how can I append strings to the end of fixed number of lines (fixed position). I am trying and searching books and websites for my answer but I couldn't find what I am doing wrong.
My structure :
const int numberofdays=150 ;
const int numberofstudents=2;
struct students
{
char attendance[numberofdays]; int rollno;
char fullname[50],fathersname[50];
}
Creating a text file
ofstream datafile("data.txt", ios::out );
Then I take input from the user and save it to the file.
How I save my data to text files :
datafile <<attendance <<endl<< rollno <<endl<<
fullname <<endl<< fathersname <<endl ;
How it looks like in text files :
p // p for present - 1st line
1 // roll number
Monte Cristo // full name
Black Michael // Fathers name
a // a for absent - 5th line
2 // roll number
Johnson // full name
Nikolas // Fathers name
How I try to update the file. (updating attendance for everyday)
datafile.open("data.txt", ios::ate | ios::out | ios::in);
if (!datafile)
{
cerr <<"File couldn't be opened";
exit (1);
}
for (int i=1 ; i<=numberofstudents ; i++)
{
long int offset = ( (i-1) * sizeof(students) );
system("cls");
cout <<"\t\tPresent : p \n\t\t Absent : a"<<endl;
cout <<"\nRoll #"<<i<<" : ";
cin >> ch1;
if (ch1 != 'p')
ch1 = 'a';
datafile.seekp(offset);
datafile <<ch1;
datafile.seekg(0);
}
I just want to add (append) characters 'p' or 'a' to the first or fifth line, I tried every possible way but I am unable to do it.
What you are doing is fairly common, but as you say it is inefficient if the size of data grows. Two solutions are to have fixed size records and index files.
For fixed-size records, in the file write the exact bytes of your data structure rather than a variable length text. This would mean you don't have a text file any more, but a binary file. You can then calculate the position to seek to easily.
To create an index file, write two files at once, one your variable size record file, and the other write a binary value with either the offset of the data from the start of the file. Since the index is a fixed size, you can seek to the index, read it, then seek to the position in the data file. If the new record will fit, you can update it in place, otherwise fill in with blanks and put the updated record at the end of the data file, then update the index file to point to the new location. This is basically how early PC databases worked.
Fixed size records are rather inflexible, and by the time you've implemented the index file system and tested it, now-a-days you probably would use a in-process database instead.
I came up with my own (easy & inefficient) logic to copy every line (except the line I want to update) to the another file.
I made my text file to be created like this :
=p // p for present - 1st line
1 // roll number
Monte Cristo // full name
Black Michael // Fathers name
=a // a for absent - 5th line
2 // roll number
Johnson // full name
Nikolas // Fathers name
Then I made the following code to update 1st and 5th line :
ifstream datafile("data.txt", ios ::in);
ofstream tempfile("temp.txt" , ios ::out);
string data, ch1;
while (getline(datafile,data))
{
if (data[0]=='=')
{
system("cls");
cout <<"\t\tPresent : p\n\t\tAbsent : a"<<endl;
cout <<"\nRoll #"<<i<<" : ";
cin >> ch1;
++i;
if (ch1 != "p")
ch1 = "a";
data=data+ch1; // Appending (updating) lines.
}
tempfile <<data <<endl; // If it was 1st or 5th line, it got updated
}
datafile.close(); tempfile.close();
remove("data.txt"); rename("temp.txt" , "data.txt");
But as you can see, this logic is inefficient. I will still wait for someone to inform me if I could somehow move my file pointer to exact location (1st and 5th line) and update them.
Cheers!

(C++) - Associating strings with values read in from a file

I am trying to get a value associate with a string inside a file called invoice1.txt
invoice1.txt
hammer#10.00
saw#20.00
So for example, when I lookup "hammer" I would like the expression to evaluate to 10.00.
My code so far
string search;
ifstream inFile;
string line;
double price;
inFile.open("invoice1.txt");
if(!inFile)
{
cout << "Unable to open file" << endl;
return 0;
}
else
{
int pos;
while(inFile.good())
{
getline(inFile,line);
pos=line.find(search);
if(pos!=string::npos)
{
cout<<"The item "<<search<<" costs: "// code to get the price
}
}
}
system("pause");
This is the output I am aiming for:
The item hammer costs: 10.00
The summerise, my question is:
How can I associate values with one another that are read in from a file, so I can get a price for an item without having to reparse the file and find it again?
This is what std::map is for.
What you want to do is break your problem down into multiple stages. Here is a simple set of steps that should help you (there are better ways, but I'm trying to keep things simple here).
I've added some lines to explain how to use std::map, in case you're not familiar.
Read the file line by line.
For each line that is read in, get the value after the '#' character.
Add the value to the map, using the string before '#' as the key...
priceMap[key] = price; // for example, this might evaluate to: myMap["hammer"] = 10.00
When you want to use the value, simple give the map you're key.
std::cout << priceMap["hammer"];
What do you search in line from file? You have to search for character # and split your string into two parts.
getline(inFile,line);
pos=line.find('#');
if(pos!=string::npos)
cout<<"The item "<<line.substr(0,pos)<<" costs: " << line.substr(pos+1,line.size()-1) << endl;// code to get the price
You can save item name and price in different variables if you want. If you want to do something more with a string, read this for further instructions.

search for specific row c++ tab delmited

AccountNumber Type Amount
15 checking 52.42
23 savings 51.51
11 checking 12.21
is my tab delmited file
i would like to be able to search for rows by the account number. say if i put in 23, i want to get that specific row. how would id do that?
also more advance, if i wanted to change a specific value, say amount 51.51 in account 23. how do i fetch that value and replace it with a new value?
so far im just reading in row by row
string line;
ifstream is("account.txt");
if (is.is_open())
{
while (std::getline(is, line)) // read one line at a time
{
string value;
string parseline;
std::istringstream iss(line);
getline(line, parseline);
cout << parseline << endl; // do something with the value
while (iss >> value) // read one value at at time from the line
{
//cout << line << " "; // do something with the value
}
}
is.close();
}
else
cout << "File cant be opened" << endl;
return 0;
Given that each line is of variable length there is no way to index to particular row without first parsing the entire file.
But I suspect your program will want to manipulate random rows and columns. So I'd start by parsing out the entire file. Put each row into its own data structure in an array, then index that row in the array.
You can use "strtok" to split the input up into rows, and then strtok again to split each row into fields.
If I were to do this, I would first write a few functions that parse the entire file and store the data in an appropriate data structure (such as an array or std::map). Then I would use the data structure for the required operations (such as searching or editing). Finally, I would write the data structure back to a file if there are any modifications.