C++ text file into array. (Newbie) - c++

Hello everyone and sry in advance for the newbie question but i didn't find any topic specific to my problem. I have a text file of products as shown below:
//No. //Description //Price
100 Office_seat 102.99
200 Desk 224.99
300 Computer_desk 45.49
400 Desk_Lamb 23.99
500 Bookcase 89.49
i want to read it and save it in an array from which i will search for the Product_pin later and calculate the total price of a client's purchase.
tried something like the code i am posting but i think i am starting it all wrong. I would be gratefull for any advice.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
ifstream file("Proionta.txt");
if(file.is_open())
{
string myArray[15];
for(int i=0;i<15;i++)
{
file>>myArray[i];
}
}
system ("pause");
}
Should i try to make a function to put the code in it?

Let's start out with the record modeling concept, then get primitive.
You want to model the text line as a record:
struct Record
{
unsigned int number;
std::string description;
double price;
};
The next step would be to overload operator>> for the Record:
struct Record
{
unsigned int number;
std::string description;
double price;
friend std::istream& operator>>(std::istream& input, Record& r);
};
std::istream& operator>>(std::istream& input, Record& r)
{
input >> r.number >> r.description >> r.price;
return input;
}
Using the above code, you can read in a file:
std::vector<Record> database;
Record r;
while (my_text_file >> r)
{
database.push_back(r);
}
Edit 1: Without struct
Let's say you don't know about how to use class or struct.
Each field can be read separately:
unsigned int number;
std::string description;
double price;
while (my_text_file >> number >> description >> price)
{
// Do something with number, description, price
}
Edit 2: Arrays vs. vector
Many assignments require you to do something with the data, like averages or searches. This usually requires you to save the data.
Two popular containers (from a student's point of view) are the array and std::vector.
Arrays are not a good choice, because with File I/O, you're never quite sure how many records there are and arrays like to be static in capacity (never changing). So you will need to do the resizing yourself:
static const unsigned int initial_capacity = 16U;
Record database[initial_capacity];
unsigned int capacity = initial_capacity;
Record r;
unsigned int items_read = 0;
while (my_text_file >> r)
{
if (items_read < capacity)
{
database[items_read] = r;
++items_read;
}
else
{
// Allocate new, larger array
// Copy items from old array to larger array.
// Update capacity variable.
// Delete old array
// Change database pointer to new array
}
}
A nice feature of std::vector is that you can access it like an array, and it will automatically increase in capacity as needed.

Related

What is the problem I am having with using arrays with classes?

I have been working on a project for my computer science class and have encountered an issue with the code working. I am shown no error except when I try to compile and I get an error that reads:
Exception thrown: write access violation.
_Left was 0xCCCCCCCC.
The purpose of my project is to take a list of names from an external file, read them into an array, sort said array and then output the sorted list all while using a class for the code.
Here is a copy of my code and I would like to extend my gratitude to whoever can help me through my issue:
**Header File**
#include <iostream>
using namespace std;
class person
{
public:
person();
bool get(ifstream&);
void put(ofstream&);
private:
int capacity = 0;
string first_name[CAPACITY];
string last_name[CAPACITY];
int age[CAPACITY];
};```
**Header function definitions cpp file**
#include<iostream>
#include<string>
#include<fstream>
#include<cstdlib>
const int CAPACITY=20;
using namespace std;
#include "Person.h"
//Names constructor
//Postcondition both first name and last name initialized to zero
person::person()
{
first_name[CAPACITY] = "";
last_name[CAPACITY] = "";
age[CAPACITY]=0;
}
bool person::get(ifstream& in)
{
in >> first_name[CAPACITY] >> last_name[CAPACITY] >> age[CAPACITY];
return(in.good());
}
void person::put(ofstream &out)
{
out << first_name[CAPACITY] << last_name[CAPACITY] << age[CAPACITY];
}
**cpp file which holds main**
#include<iostream>
#include<cstdlib>
#include<fstream>
#include<string>
const int CAPACITY = 20;
using namespace std;
#include "Person.h"
void pop(string *xp, string *yp);
void sort(string name[CAPACITY], int count);
int main()
{
class person names[CAPACITY];
ifstream infile;
ofstream outfile;
string filename;
string name[CAPACITY];
int n = 0;
cout << "Enter the file name you wish to open" << endl;
cin >> filename;
infile.open(filename + ".txt");
outfile.open("Person_New.txt");
if (infile.fail())
{
cout << "The file requested did not open" << endl;
exit(1);
}
while (!infile.eof())
{
names[n].get(infile);
n++;
}
sort(name, CAPACITY);
for (int i = 0; i < CAPACITY; i++)
{
names[i].put(outfile);
}
cout << "The file has been created" << endl;
infile.close();
}
void pop(string *xp, string *yp)
{
string temp = *xp;
*xp = *yp;
*yp = temp;
}
void sort(string name[CAPACITY], int count)
{
int i, j;
for (i = 0; i < count - 1; i++)
{
for (j = 0; j < count - i - 1; j++)
{
if (name[j] > name[j + 1])
{
pop(&name[j], &name[j + 1]);
}
}
}
}
Once again Thank you for any support
It sounds to me like the compiler is getting upset that you are trying to write (i.e. assign a value) at an address that you do not have permission to access. I believe your constructor for the class person might be at fault because of how this class stores its variables, as well as the class header:
Constructor for the class person:
`person::person(){
first_name[CAPACITY] = "";
last_name[CAPACITY] = "";
age[CAPACITY] = 0;
}`
Class header for the class person:
`class person{
public:
//stuff
private:
int capacity = 0;
std::string first_name[CAPACITY];
std::string last_name[CAPACITY];
int age[CAPACITY];
//more stuff
}`
C++ is very specific about its naming conventions, so it makes a distinction between capacity and CAPACITY. Because of this, the variable CAPACITY is not defined within the Person.h file.
Also, because CAPACITY is set to a fixed value in your Person.cpp file, whenever you use first_name[CAPACITY], last_name[CAPACITY], or age[CAPACITY] to assign new values, you are only updating the values at the index equal to CAPACITY unless you update the value of CAPACITY itself. In the code you provided, CAPACITY is equal to 20, so your program attempts to update exclusively index 20 with each method call. This will likely cause issues since the person class only attempts to make its arrays on the runtime stack, with a size of 0 each.
Separately, it seems like you want an array of people, but it appears that you are attempting to use a single person object to store the names and ages of multiple people by making these all arrays. Instead, I would recommend making first_name, last_name, and age not arrays, but rather single variables. Then, you can manipulate an array of type person using your CAPACITY variable. You got pretty close, but you can instead declare it as person myPersonArray[CAPACITY] (no need to mention "class" in front of it -- just be sure that you have #include "Person.h" in your main.cpp file). When you want to update a specific person, you can perform an operation like myPersonArray[updateThisIndexNum].update(newFirstName, newLastName, newAge) or some logical equivalent.
As a final note, I almost always highly recommend against using !infile.eof() to control your while loop when reading any file because eof() only indicates whether you have tried to read past the end of an input file. I would highly recommend checking out this post on Stack Overflow where people far more knowledgeable than I explain exactly why this is usually dangerous and how to avoid it.

Passing a dynamic array of structs c++

I need to read a .txt file and use the first number as the array size in a function called getData.
In my code, I am able to read the file and assign it to the array size as listSize. I am also able to fill the rest of the array with the .txt information. When I print out what is in my array WITHIN the getData function, it works.
The problem is that when I try to access the array outside of the getData function my program crashes. I am new to pointers, and c++ in general. I don't think I am passing it or calling it correctly. I have had a hard time finding information to assist me in the problem.
How can I access the arrays I created in getData?
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
using namespace std;
struct menuItemType
{
string menuItem;
double menuPrice;
};
void getData(int& listSize, menuItemType menuList[], int orderList[]);
int main()
{
menuItemType *menuList = 0; //-----pointers
int *orderList = 0;
int listSize;
getData(listSize, menuList, orderList);
cout << menuList[0].menuItem; //-----This is what crashes the program
return 0;
}
//-----Get Menu Function
void getData(int& listSize, menuItemType menuList[], int orderList[])
{
//-----Declare inFile
ifstream inFile;
string price, size;
//-----Open inFile
inFile.open("Ch9_Ex5Data.txt");
//-----Get Amount of Items, Convert to int
getline(inFile, size);
listSize = stoi(size);
//-----Set Array Size
menuList = new menuItemType[listSize];
orderList = new int[listSize];
//-----Get Menu
for (int x = 0; x < listSize; x++)
{
//-----Get menuItem
getline(inFile, menuList[x].menuItem);
//-----Get menuPrice convert to double
getline(inFile, price);
menuList[x].menuPrice = stod(price);
}
//------PRINT WORKS HERE ----- This print made me think i created the
//arrays correctly
for (int x = 0; x < listSize; x++)
{
cout << menuList[x].menuItem << endl
<< menuList[x].menuPrice
<< endl;
}
inFile.close();
}
The contents of the .txt
8
Plain Egg
1.45
Bacon and Egg
2.45
Muffin
0.99
French Toast
1.99
Fruit Basket
2.49
Cereal
0.69
Coffee
0.50
Tea
0.75
Setting menuList and orderList in getData does not update the pointers in main. It would if you used references to pointers:
void getData(int& listSize, menuItemType*& menuList, int*& orderList);
Even better, use references to std::vector and quit mucking around with owning pointers and new and delete.
Let's Rewrite your code for a better C++ness, with explanations. :)
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
Don't do using namespace std just because you can type less things, namespaces helps you by telling you where this particular thing you invoked came from. if you really wanna write string instead of std::string, pull that particular thing, not the whole namespace, like this:
using std::string;
Your struct seems right, but you need to choose if your types will start with capitals or not, I always start my types with capitals but this is a choice:
struct MenuItemType
{
string menuItem;
double menuPrice;
};
Now, your getData should, well, get your data. so the type matters. your data is not 'void' as you declared, it's an array of MenuItemType, you can then declare them as vector and not even care about pointers.
Other thing: all of your parameters in getData shouldn't be parameters - they are all things that you would get from the text file that your program will parse, so the only thing that matters for the getData is the text file, so this is your variable.
std::vector<MenuItemType> getData(const std::string& textFile)
{
std::ifstream inFile;
std::string price, size, item;
inFile.open(textFile);
getline(inFile, size);
int listSize = stoi(size);
std::vector<MenuItemType> result;
result.reserve(listSize);
for (int x = 0; x < listSize; x++)
{
getline(inFile, item);
getline(inFile, price);
result.push_back(MenuItemType{item, stod(price)});
}
return result;
}
See how I didn't closed the file? It will be closed as soon as you leave the function, there's no need to call that unless you need the file to close before the function finishes.
Thumbs up rule: don't deal with pointers unless you have to.
As for your main function:
int main()
{
std::vector<MenuItemType> menuList = getData("Ch9_Ex5Data.txt");
cout << menuList[0].menuItem;
return 0;
}
You could rewrite that in a faster way if you are sure what types are you using, the code above is equivalent to this one:
int main()
{
auto menuList = getData("Ch9_Ex5Data.txt");
cout << menuList[0].menuItem;
return 0;
}

How do you make a vector of class objects?

I'm a bit confused as to how vectors work. What I'm trying to do is create a vector of 5 TaxBill objects. Then, what I want to do is read from an input file that has the names and different tax rates for 5 states. I want to store the name of the state in the object and the tax rates of the state in an array in int main().
Here's the input file called "Tax Rates.dat". The numbers are the sales, property and income tax rate, respectively, for each state.
TEXAS .0825 .02 -.03
MARYLAND .065 .04 .05
OHIO .03 .025 .03
CALIFORNIA .095 .055 .045
MAINE .02 .015 .02
Here's my class interface called "Tax Bill.h".
using namespace std;
class TaxBill
{
public:
void setValue(string, int);
void dataValid(double&, double&, double&);
private:
string Name;
int index;
double taxBill;
}
Here's my class implementation called "Tax Bill.cpp".
#include "Tax Bill.h"
void TaxBill::setValue(string name, int x)
{}
void TaxBill::dataValid(double& a, double& b, double& c)
{
if(a < 0)
a = 0;
if(b < 0)
b = 0;
if(c < 0)
c = 0;
return;
}
Here's my main source code so far.
#include <iostream>
#include <string>
#include <iomanip>
#include <fstream>
#include <vector>
#include "Tax Bill.h"
using namespace std;
int main()
{
const int SALARY = 100000,
HOUSE = 246000,
PURCHASE = 36000;
ifstream fin;
fin.open("Tax Rates.dat");
vector <TaxBill> someVector (5);
double sales,
property,
income;
double taxRates[5][3];
string name;
if(!fin)
return 0;
else
{
for(int i = 0; fin >> name >> sales >> property >> income; i++)
{
dataValid(sales, property, income);
taxRates[i][0] = sales;
taxRates[i][1] = property;
taxRates[i][2] = income;
}
}
The for loop is where I want to store the name of the state read from the input file and i into the string Name and index of the class object. The reason for the index is because later in the program I want to sort the objects in the vector alphabetically but not the array where the corresponding tax rates are stored.
I also don't want to use the function push_back().
I guess my question is, how do I make an vector of 5 class objects and access them?
Please keep in mind that my program is hardly complete and it's this one hurdle that's holding me back.
Here example of using vector from your code. Here you declare
vector <TaxBill> someVector (5);
So now, you have someVector[0] - [4] (5 in total). To use it, actually you just have to assign it like an normal array.
someVector[0].{insert property here}
But wait, in your class, there is no clear way to set the string Name and Index. So i think you forget to place it here, hence i make my own in the class.
class TaxBill
{
public:
void setValue(string Name, int Index){
name = Name; index = Index;
}
void dataValid(double&, double&, double&);
private:
string name;
int index;
double taxBill;
}
Now to use the vector, i just used the property this way
someVector[0].setValue("someName",1);
Tada, you get it to works. Btw, i dont know why you declare a procedure in the class, but you want to used it multiple times in main program. I mean this one
dataValid(sales, property, income);
to used it, i suggest you make a procedure in main program rather than in class and anyway that line should produce an error anyway. :)

String in struct in struct in C++

So I've to do another exercise. This time I need to define a struct and a 100-elements array, which will store information about the book (title, author, ID number, price) and a simple function which will print info about all of the books stored. I started with that code:
#include <iostream>
using namespace std;
int main()
{
struct name_surname {string name, surname;};
struct book {string title; name_surname author_name, author_surname; int ID; int price;};
return 0;
}
And, well, what now? How can I store this in an array?
You just create an array of type book or name_surname or whatever you want.
Example:
book arr[100];
arr[0].title = "The last robot";
arr[0].ID = 2753;
Tips:
It's good programming practice if your structs/classes begin with with capital letter, so it's easier to distinguish them and so it is easier to name the variable the same name just without the capital letter. Example.
struct Name_surname
{
string name, surname;
};
Name_surname name_surname[100];
name_surname[0].name = "MyName";
Another tip is that I'd really suggest you learn how to research, this question has been answered millions of times and answers are all over the internet.
Here is my suggestion :
struct book
{
string title;
string name_surname;
string author_name;
string author_surname;
int ID;
int price;
};
struct Database
{
book *array;
void printDatabase()
{
for(int i = 0 ; i < 100 ;i++)
cout<<array[i].title<<endl;
}
Database()
{
array = new string [100];
}
};
Your name structure seems a little confused but creating an array is simply a case of declaring a variable with [] appended to it giving the size.
For example:
struct full_name
{
std::string firstname;
std::string surname;
};
struct book
{
std::string title;
full_name author;
int ID;
int price;
};
int main()
{
// Declare an array using []
book books[100]; // 100 book objects
// access elements of the array using [n]
// where n = 0 - 99
books[0].ID = 1;
books[0].title = "Learn To Program In 21 years";
books[0].author.firstname = "Idont";
books[0].author.surname = "Getoutalot";
}
What do you think about that:
#include <iostream>
using namespace std;
struct book {string title; string name; int ID; int price;} tab[100];
void input(book[]);
void print(book[]);
int main()
{
input(tab);
print (tab);
return 0;
}
void input(book tab[])
{
for (int i=0;i<3;i++)
{
cout<<"\nBook number: "<<i+1<<endl;
cout<<"title: ";cin>>tab[i].title;
cout<<"name: ";cin>>tab[i].name;
cout<<"ID: ";cin>>tab[i].ID;
cout<<"price: ";cin>>tab[i].price;
}
}
void print (book tab[])
{
for (int i=0; i<3; i++)
{
cout<<"\nBook number: "<<i+1<<endl;
cout<<"title: "<<tab[i].title;
cout<<"\nname: "<<tab[i].name;
cout<<"\nID: "<<tab[i].ID;
cout<<"\nprice: \n"<<tab[i].price;
}
}
I've done this with help from some Yt video. It works, but, is there a way to do it better, or just leave it how it is? And I have a question: Why those function parameters? Can't I just say tab[] or something else?
Computer languages are based on general and recursive rules. Just try to experiment and extrapolate with the basic understanding to build seemingly complex stuff. Coming to what you are trying to achieve:
We know, an array can be declared for any data-type (primitive or derived, one might call them POD and ADT).
We know, struct can comprise of any number of elements of any data-types.
Now, we can see that it is just as natural to say MyStruct[] as it is to int[].
It is better to prefer std::array if using modern compiler.

Reading input into Vector Objects

Hi I am attempting to read data into a vector of objects but I am having trouble doing so. I have created a class and a vector of that class. When I try to read data into the the vector I get class Bank Statements has no member and then the variables i attempt to read in.
#include <iostream>
#include<vector>
#include <string>
using namespace std;
class Bank_Statement
{
public:
Bank_Statement();
Bank_Statement(int d, double bal, string desc);
private:
string description;
double balance;
int day;
};
Bank_Statement::Bank_Statement(int d, double bal, string desc)
{
description = desc;
balance = bal;
day = d
}
int main(){
Bank_Statement statement1;
cin >> statement1.d >> statement1.bal >> statement1.desc;
vector<Bank_Statement> user_statements;
int day_of_month;
for (day_of_month = 0, day_of_month < user_statements.size(); day_of_month++){
user_statements.push_back(statement1);
}
return 0;
}
The argument names of the constructor are not data members of the class. When you did:
cin >> statement1.d >> statement1.bal >> statement1.desc;
That is not right because those aren't members declared in the class. Use description, balance, and day respectively instead.
It doesn't even enter the loop. When the vector is created, its size is zero. This means that the expression day_of_month < user_statements.size() (the loop condition) will always be false.
You should read the input in the loop, something like
Bank_Statement statement;
std::vector<Bank_Statement> user_statements;
while (std::cin >> statement.d >> statement.bal >> statement.desc)
{
user_statements.push_back(statement);
}
Thats because of the condition day_of_month < user_statements.size(). Initially vector is empty and does not satisfy the condition to do a push_back operation on the vector.