I'm a beginner in programming and i'm trying to read my .txt file into an array of struct in this program which after that display the data and then sort it, but the program only reads the first line and the loop won't stop until arraysize.
The file data looks like this:
ID NAME ADDRESS AGE
The Code:
#include <iostream>
#include <fstream>
#include <string>
#include <conio.h>
using namespace std;
struct bio
{
char name[50], address[50];
int id, age;
};
int main()
{
int i = 0, arraysize = 1000;
bio b[arraysize];
fstream data;
data.open("biodata.txt");
while(data.read((char*)&b, sizeof(b[i])))
{
for (i = 1; i < 1000; i++)
{
data >> b[i].id >> b[i].name >> b[i].address >> b[i].age;
}
}
for (i = 0; i < 1000; i++)
{
cout << b[i].id << " " << b[i].name << " " << b[i].address << " " << b[i].age << " " << endl;
}
data.close();
getch();
}
#include <iostream>
#include <fstream>
#include <string>
#define ARRAY_SIZE 1000
#define FILE_NAME "biodata.txt"
using namespace std;
struct Bio
{
int m_id;
string m_name;
string m_address;
int m_age;
};
int main()
{
Bio bio[ARRAY_SIZE];
ifstream data;
data.open(FILE_NAME);
if (!data)
{
cout << "not file " << FILE_NAME;
return 0;
}
for (int i = 0; i < ARRAY_SIZE && data.good(); ++i)
{
data >> bio[i].m_id >> bio[i].m_name >> bio[i].m_address >> bio[i].m_age;
}
for (int i = 0; i < ARRAY_SIZE ; ++i)
{
cout << bio[i].m_id << " " << bio[i].m_name << " " << bio[i].m_address << " " << bio[i].m_age << " " << endl;
}
data.close();
}
a few comments:
for what conio lib?
struct (bio) start with capital letter
don't use in char array in c++, you have string for this.
separate the variables to separate lines (bot "char name[50], address[50];")
better to rename members to m_X
about your "arraysize". if it const number you decide, do it with #define. if you need the whole file, you don't need it at all. (the file name too)
ifstream and not fstream data. you need just read. you don't want to change your data with some mistake.
check it the file opened well
in your code you check the while just before the loop.
in your condition loop check data.good(). it check it not eof and he file is readable.
read command is for binary file
it's better to separate the load file and print data to 2 differents functions. I didn't do it for save on your template
The following is maybe a little complicated for beginners, but since we are talking about C++, we should look also to a "more" objective oriented approach.
You designed a class, called bio. In object oriented languages you will put all data for an object and also all functions that operate on this data in the class. So you need to add member functions. The idea is that you encapsulate all data in an object. The outside world should not know anything about the details of the class. You just access it via member functions. And if you want to make changes later than you will do this within the member functions of the classes. And the rest of the program will continue to work.
Additionally we should definitely use C++ language features. For examples you should use std::string for strings and not Plain old C-Style char arrays. You should basically never use C-Style arrays in C++. Instead, please use STL container.
So, then let's design a class with data members and member functions. Since at the moment we just need input and output functionality, we overwrite the inserter and extractor operator. These operators know abot the data and behaviour of the class and will take care.
See the following program:
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
#include <sstream>
struct Bio
{
// Data
unsigned int id{};
std::string name{};
std::string address{};
unsigned int age{};
// Overload extractor operator to read all data
friend std::istream& operator >> (std::istream& is, Bio& b) {
std::string textLine{};
if (std::getline(is, textLine)) {
std::istringstream textLineStream{textLine};
textLineStream >> b.id >> b.name >> b.address >> b.age;
}
return is;
}
// Overload inserter operator to print the data
friend std::ostream& operator << (std::ostream& os, const Bio& b) {
return os << b.id << " " << b.name << " " << b.address << " " << b.age;
}
};
std::istringstream sourceFile{R"(1 John Address1 31
2 Paul Address2 32
3 Ringo Address3 33
4 George Address4 34
)"};
int main()
{
// Define Variable and read complete source file
std::vector<Bio> bio{std::istream_iterator<Bio>(sourceFile), std::istream_iterator<Bio>()};
// Sort the guys by name
std::sort(bio.begin(), bio.end(), [](const Bio& b1, const Bio& b2){ return b1.name < b2.name;});
// Show output on screen
std::copy(bio.begin(),bio.end(),std::ostream_iterator<Bio>(std::cout, "\n"));
return 0;
}
Some comments. On StackOverflow, I cannot use files. So in my example program, I use a std::istringstream instead. But this is also an std::istream. You can use any other std::istream as well. So if you define an `````std::ifstreamto read from a file, then it will work in the same way as thestd::istringstream````.
And please see. The extractor operator does the whole work of reading the source File. It is encapsulated. No outside function needs to know, how it does.
In the main function, we define a std::vector and use its range contructor to specifiy where the data comes from. We give it the std::istream_iterator, which iterates over the input data and calls the extractor operator until verything is read.
Then we sort by names and copy the result to the output.
You may notice that fields in your input data are separted by space. This does in general not work for none atomic data. The name could exist of 2 parts and the address can have a street and a city. For this CSV (Comma separated Values) files have been invented.
Please see a more realistic soultion below.
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
#include <sstream>
#include <regex>
struct Bio
{
// Data
unsigned int id{};
std::string name{};
std::string address{};
unsigned int age{};
// Overload extractor operator to read all data
friend std::istream& operator >> (std::istream& is, Bio& b) {
std::string line{};
std::regex re{";"};
if (std::getline(is, line)) {
std::vector<std::string> token{std::sregex_token_iterator(line.begin(), line.end(), re, -1), std::sregex_token_iterator()};
if (4 == token.size()) {
b.id = std::stoul(token[0]);
b.name = token[1];
b.address = token[2];
b.age = std::stoul(token[3]);
}
}
return is;
}
// Overload inserter operator to print the data
friend std::ostream& operator << (std::ostream& os, const Bio& b) {
return os << b.id << ", " << b.name << ", " << b.address << ", " << b.age;
}
};
std::istringstream sourceFile{R"(1; John Lenon; Street1 City1; 31
2; Paul McCartney; Street2 City2; 32
3; Ringo Starr; Street3 City3; 33
4; George Harrison; Address4; 34
)"};
int main()
{
// Define Variable and read complete source file
std::vector<Bio> bio{std::istream_iterator<Bio>(sourceFile), std::istream_iterator<Bio>()};
// Sort the guys by name
std::sort(bio.begin(), bio.end(), [](const Bio& b1, const Bio& b2){ return b1.name < b2.name;});
// Show output on screen
std::copy(bio.begin(),bio.end(),std::ostream_iterator<Bio>(std::cout, "\n"));
return 0;
}
We have a new source format and main is unchanged. Just the extractor operator is modified. Here we are using a different iterator to get the source data.
Related
C++ question!
I have a .txt file with this info:
james, watson
brittany,blake
roger,tra4#pos
jonathan, pote5
amber,Trisa123!
where the first column is name and the second one is the Id of website users.
I need to read this file and then store the information into 2 arrays:
name[]
user_Id []
Could you please help me? I found the solution for saving it into a 2d vector but I prefer to save it as arrays since I need to compare the string values with another string (received by user to check if her name/user Id is already in the system or not)
I found the solution for saving it into a 2d vector but not for arrays.
I will show you your requested solution, but I am sorry to inform you that the solution approach is wrong. For various reasons. First, and most important: In C++ C-Style arrays should in general not not be used.
C-Style arrays have fixed size and are not dyanmic. So, you will always come up with a magic number of an estimated max size. The correct approach would be to use a dynamic container. And for your solution, the std::vector is most appropriate.
Then, it is a very bad idea to have to separate arrays for related data. The correct approach is to put related data in a struct and then create a std::vector of this struct. Otherwise you will have always to maintain and handle always 2 arrays, and you may even lose the sync between related data.
Anyway, I will first show you a solution following your idea:
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
using namespace std;
const unsigned int MagicNumberForMaxArraySize = 42;
int main() {
// Define Arrays to hold the user and their IDs
string user[MagicNumberForMaxArraySize]{};
string user_ID[MagicNumberForMaxArraySize]{};
// Open the file and check, if it could be opened
ifstream ifs("test.txt");
if (ifs.is_open()) {
unsigned int index = 0;
// Read all lines and put result into arrays
while ((index < MagicNumberForMaxArraySize) and
(getline(getline(ifs, user[index], ',') >> ws, user_ID[index]))) {
// Now we have read a comlete line. Goto next index
++index;
}
// Show debug output
for (unsigned int i = 0; i < index; ++i)
cout << "User: " << user[i] << "\tID: " << user_ID[i] << '\n';
}
else
cout << "\n\n*** Error: Could not open source file\n\n";
}
But I would not recommend to go on with that. The next improvement would be to use a struct and then an array of struct. Additionaly, I will get rid of using namespace std; which should never be used. And, I initialize varaibles with the universal initializer.
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
const unsigned int MagicNumberForMaxArraySize = 42;
struct Data {
std::string user{};
std::string ID{};
};
int main() {
// Define array for our needed data
Data data[MagicNumberForMaxArraySize];
// Open the file and check, if it could be opened
std::ifstream ifs("test.txt");
if (ifs.is_open()) {
unsigned int index = 0;
// Read all lines and put result into arrays
while ((index < MagicNumberForMaxArraySize) and
(std::getline(std::getline(ifs, data[index].user, ',') >> std::ws, data[index].ID))) {
// Now we have read a comlete line. Goto next index
++index;
}
// Show debug output
for (unsigned int i = 0; i < index; ++i)
std::cout << "User: " << data[i].user << "\tID: " << data[i].ID<< '\n';
}
else
std::cout << "\n\n*** Error: Could not open source file\n\n";
}
Evolution:
We will now introduce an object oriented principle . Data and methods operating on this data shall be in one class or struct. Hence, we will add IO methods to the struct, and add an aditional struct for holding all users. Also, the new if-statement with initializer can be used. And of course the std::vector.
Please see:
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include <vector>
// Struct to hold properties for one user
struct User {
std::string name{};
std::string ID{};
// Simple extraction
friend std::istream& operator >> (std::istream& is, User& user) {
std::getline(std::getline(is, user.name, ',') >> std::ws, user.ID);
return is;
}
// Simple inserter
friend std::ostream& operator << (std::ostream& os, const User& user) {
return os << "User: " << user.name << "\tID: " << user.ID;
}
};
// This class will contain all users
struct Data {
std::vector<User> users{};
// Simple extraction
friend std::istream& operator >> (std::istream& is, Data& d) {
// Delete potential existing old data
d.users.clear();
// Now read all users
for (User temp{}; is >> temp; d.users.push_back(std::move(temp)));
return is;
}
// Simple inserter
friend std::ostream& operator << (std::ostream& os, const Data& d) {
for (const User& u : d.users) os << u << '\n';
return os;
}
};
int main() {
// Open the file and check, if it could be opened
if (std::ifstream ifs("test.txt");ifs) {
// Read all data and show result
if (Data data{}; not (ifs >> data).bad())
std::cout << data;
}
else
std::cout << "\n\n*** Error: Could not open source file\n\n";
}
You can also use strtok() from cstring library to split string into tokens: Split string in C/C++
I want to read a csv data to vector of struct in cpp, This is what I wrote, I want to store the iris dataset in pointer of struct vector csv std::vector<Csv> *csv = new std::vector<Csv>;
#include <vector>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
struct Csv{
float a;
float b;
float c;
float d;
std::string e;
};
int main(){
std::string colname;
// Iris csv dataset downloaded from
// https://gist.github.com/curran/a08a1080b88344b0c8a7
std::ifstream *myFile = new std::ifstream("iris.csv");
std::vector<Csv> *csv = new std::vector<Csv>;
std::string line;
// Read the column names
if(myFile->good())
{
// Extract the first line in the file
std::getline(*myFile, line);
// Create a stringstream from line
std::stringstream ss(line);
// Extract each column name
while(std::getline(ss, colname, ',')){
std::cout<<colname<<std::endl;
}
}
// Read data, line by line
while(std::getline(*myFile, line))
{
// Create a stringstream of the current line
std::stringstream ss(line);
}
return 0;
}
I dont know how to implement this part of the code which outputs line with both float and string.
// Read data, line by line
while(std::getline(*myFile, line))
{
// Create a stringstream of the current line
std::stringstream ss(line);
}
Evolution
We start with you program and complete it with your current programm style. Then we analyze your code and refactor it to a more C++ style solution. In the end we show a modern C++ solution using more OO methods.
First your completed code:
#include <vector>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
struct Csv {
float a;
float b;
float c;
float d;
std::string e;
};
int main() {
std::string colname;
// Iris csv dataset downloaded from
// https://gist.github.com/curran/a08a1080b88344b0c8a7
std::ifstream* myFile = new std::ifstream("r:\\iris.csv");
std::vector<Csv>* csv = new std::vector<Csv>;
std::string line;
// Read the column names
if (myFile->good())
{
// Extract the first line in the file
std::getline(*myFile, line);
// Create a stringstream from line
std::stringstream ss(line);
// Extract each column name
while (std::getline(ss, colname, ',')) {
std::cout << colname << std::endl;
}
}
// Read data, line by line
while (std::getline(*myFile, line))
{
// Create a stringstream of the current line
std::stringstream ss(line);
// Extract each column
std::string column;
std::vector<std::string> columns{};
while (std::getline(ss, column, ',')) {
columns.push_back(column);
}
// Convert
Csv csvTemp{};
csvTemp.a = std::stod(columns[0]);
csvTemp.b = std::stod(columns[1]);
csvTemp.c = std::stod(columns[2]);
csvTemp.d = std::stod(columns[3]);
csvTemp.e = columns[4];
// STore new row data
csv->push_back(csvTemp);
}
// Show everything
for (const Csv& row : *csv)
std::cout << row.a << '\t' << row.b << '\t' << row.c << '\t' << row.d << '\t' << row.e << '\n';
return 0;
}
The question that you have regarding the reading of the columns from your Csv file, can be answered like that:
You need a temporary vector. Then you use the std::getline function, to split the data in the std::istringstream and to copy the resulting substrings into the vector. After that, we use string conversion functions and assign the rsults in a temporary Csv struct variable. After all conversions have been done, we move the temporary into the resulting csv vector that holds all row data.
Analysis of the program.
First, and most important, in C++ we do not use raw pointers for owned memory. We should ven not use new in most case. If at all, std::unique_ptrand std::make_unique should be used.
But we do not need dynamic memory allocation on the heap at all. You can simply define the std::vector on the functions stack. Same like in your line std::string colname; you can also define the std::vector and the std::ifstream as a normal local variable. Like for example std::vector<Csv> csv{};. Only, if you pass this variable to another function, then use pointers, but smart pointers.
Next, if you open a file, like in std::ifstream myFile("r:\\iris.csv"); you do not need to test the file streams condition with if (myFile->good()). The std::fstreams bool operator is overwritten, to give you exactly this information. Please see here.
Now, next and most important.
The structure of your source file is well known. There is a header with 5 elements and then 4 doubles and at then end a string without spaces. This makes life very easy.
If we would need to validate the input or if there would be spaces within an string, then we would need to implement other methods. But with this structure, we can use the build in iostream facilities. The snippet
// Read all data
Csv tmp{};
char comma;
while (myFile >> tmp.a >> comma >> tmp.b >> comma >> tmp.c >> comma >> tmp.d >> comma >> tmp.e)
csv.push_back(std::move(tmp));
will do the trick. Very simple.
So, the refactored solution could look like this:
#include <vector>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
struct Csv {
float a;
float b;
float c;
float d;
std::string e;
};
int main() {
std::vector<Csv> csv{};
std::ifstream myFile("r:\\iris.csv");
if (myFile) {
if (std::string header{}; std::getline(myFile, header)) std::cout << header << '\n';
// Read all data
Csv tmp{};
char comma;
while (myFile >> tmp.a >> comma >> tmp.b >> comma >> tmp.c >> comma >> tmp.d >> comma >> tmp.e)
csv.push_back(std::move(tmp));
// Show everything
for (const Csv& row : csv)
std::cout << row.a << '\t' << row.b << '\t' << row.c << '\t' << row.d << '\t' << row.e << '\n';
}
return 0;
}
This is already much more compact. But there is more . . .
In the next step, we want to add a more Object Oriented approch.
The key is that data and methods, operating on this data, should be encapsulated in an Object / class / struct. Only the Csv struct should know, how to read and write its data.
Hence, we overwrite the extractor and inserter operator for the Csv struct. We use the same approach than before. We just encapsulate the reading and writing in the struct Csv.
After that, the main function will be even more compact and the usage is more logical.
Now we have:
#include <vector>
#include <iostream>
#include <fstream>
#include <string>
struct Csv {
float a;
float b;
float c;
float d;
std::string e;
friend std::istream& operator >> (std::istream& is, Csv& c) {
char comma;
return is >> c.a >> comma >> c.b >> comma >> c.c >> comma >> c.d >> comma >> c.e;
}
friend std::ostream& operator << (std::ostream& os, const Csv& c) {
return os << c.a << '\t' << c.b << '\t' << c.c << '\t' << c.d << '\t' << c.e << '\n';
}
};
int main() {
std::vector<Csv> csv{};
if (std::ifstream myFileStream("r:\\iris.csv"); myFileStream) {
if (std::string header{}; std::getline(myFileStream, header)) std::cout << header << '\n';
// Read all data
Csv tmp{};
while (myFileStream >> tmp)
csv.push_back(std::move(tmp));
// Show everything
for (const Csv& row : csv)
std::cout << row;
}
return 0;
}
OK. Alread rather good. Bit there is even more possible.
We can see that the source data has a header and then Csv data.
Also this can be modelled into a struct. We call it Iris. And we also add an extractor and inserter overwrite to encapsulate all IO-operations.
Additionally we use now modern algorithms, regex, and IO-iterators. I am not sure, if this is too complex now. If you are interested, then I can give you further information. But for now, I will just show you the code.
#include <vector>
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <regex>
#include <iterator>
const std::regex re{ "," };
struct Csv {
float a;
float b;
float c;
float d;
std::string e;
// Overwrite extratcor for simple reading of data
friend std::istream& operator >> (std::istream& is, Csv& c) {
char comma;
return is >> c.a >> comma >> c.b >> comma >> c.c >> comma >> c.d >> comma >> c.e;
}
// Ultra simple inserter
friend std::ostream& operator << (std::ostream& os, const Csv& c) {
return os << c.a << "\t\t" << c.b << "\t\t" << c.c << "\t\t" << c.d << "\t\t" << c.e << '\n';
}
};
struct Iris {
// Iris data consits of header and then Csv Data
std::vector<std::string> header{};
std::vector<Csv> csv{};
// Overwrite extractor for generic reading from streams
friend std::istream& operator >> (std::istream& is, Iris& i) {
// First read header values;
if (std::string line{}; std::getline(is, line))
std::copy(std::sregex_token_iterator(line.begin(), line.end(), re, -1), {}, std::back_inserter(i.header));
// Read all csv data
std::copy(std::istream_iterator<Csv>(is), {}, std::back_inserter(i.csv));
return is;
}
// Simple output. Copy data to stream os
friend std::ostream& operator << (std::ostream& os, const Iris& i) {
std::copy(i.header.begin(), i.header.end(), std::ostream_iterator<std::string>(os, "\t")); std::cout << '\n';
std::copy(i.csv.begin(), i.csv.end(), std::ostream_iterator<Csv>(os));
return os;
}
};
// Driver Code
int main() {
if (std::ifstream myFileStream("r:\\iris.csv"); myFileStream) {
Iris iris{};
// Read all data
myFileStream >> iris;
// SHow result
std::cout << iris;
}
return 0;
}
Look at the main function and how easy it is.
If you have questions, then please ask.
Language: C++17
Compiled and tested with MS Visual Studio 2019, community edition
I'm trying to make a code that takes a structure, asks for user info and puts the data into a binary file called "output" so it can be read. I tried doing it with my code but it wasn't working. Can anybody help me fix it and tell me what I'm doing wrong?
Here is my code that i am working on.
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <string>
#include <iomanip>
#include <stdio.h>
#include <string.h>
using namespace std;
const int NAME_SIZE = 20;
struct Student{
char fname[NAME_SIZE];
int id;
};
int main() {
int choice;
fstream file;
Student person;
cout << "Populate the records of the file." << endl;
file.open("output", ios::out | ios::binary);
cout << "Populating the record with information."<< endl;
cout << "Enter the following data about a person " << endl;
cout << "First Name: "<< endl;
cin.getline(person.fname, NAME_SIZE);
cout << "ID Number: "<< endl;
cin >> person.id;
file.write(reinterpret_cast<char *>(&person), sizeof(person));
file.close();
return 0;
}
I would really appreciate any help
You are mixing between raw binary data and string data . You are writing filename which may have non printable characters after the name if the name is shorter than NAME_SIZE . Also int id is written as an integer which isn't printable .
This storage is valid if you want to store and load binary data like binary protocols .
If you want to store data as readable text you will have to serialize the data first but you won't be able to load them with simple read
the right way is to define a operator<< and operator>> for Student. Then it is a piece of cake dealing with saving and reading the structure.
std::ostream & operator<<(std::ostream & os, Student const & rhs)
{
for(int i=0; i<NAME_SIZE; ++i)
{
os << rhs.fname[i];
}
os << id;
return os;
}
std::istream & operator>>(std::istream & is, Student & rhs)
{
for(int i=0; i<NAME_SIZE; ++i)
{
is >> rhs.fname[i];
}
is >> id;
return is;
}
So when you need to save to file you just do:
file << person;
when you need to read from it:
file >> person;
P.S.: I would suggest to make the operator implementations more robust than that, maybe through special markers, so that you can detect issues while reading from the file.
I have a text file with some data in it as shown below
Employee No. Name Rate per hour Hours worked
100 Rishi 800 40
101 Albert 700 35
102 Richard 500 30
103 Roni 600 45
104 Reena 900 40
I need to display the emp no,name and salary
now i managed to display the table exactly as it is
i know to calculate the salary i need to multiply the rate and hours worked
but my teacher told us to do it by ourselves
i only managed to display it as it is in the text file
#include <iostream>
#include<fstream>
using namespace std;
int main(int argc, char** argv)
{
char ch;
ifstream inFile;
inFile.open("C:\\Users\\dolej\\OneDrive\\Desktop\\assignment.txt");
if (!inFile)
{
cout << "Unable to open file";
}
while (!inFile.eof())
{
inFile >> noskipws >> ch; //reading from file
cout << ch;
}
inFile.close();
return 0;
}
There are roundabout 42 million solutions for your problem :-)
Let me explain what part of the code needs to be improved. The basic problem is that you read the input character by character. You should take advantage from the std::istream's ability to read whatver variable type that you want and for which an inserter operator >> exists. For nearly all build in types such an operator exists. So, if you want to read an int, then you can do that via int i{0}; std::cin >> i. Same with other type of variables.
Please read in a book about the iostream library.
Then there are other improvements. Always initialize all variables. Use uniform initializer {}. Initializing a std::ifstream can automatically open a file. It will be closed by the destructor automatically. Do not use while (!inFile.eof()). Use while(infile >> something) instead.
Then, as I said, read whole variables and not only one char.
Example easy solution:
#include <iostream>
#include <vector>
#include <string>
#include <iterator>
#include <algorithm>
#include <fstream>
#include <iomanip>
int main()
{
std::ifstream infile{ "r:\\assignment.txt" };
if (infile)
{
// Read the header line
std::string header{};
std::getline(infile, header);
// Now we want to read all data in the text file
// Define variables, where we will store the data
int employeeNumber{ 0 };
std::string name{};
int ratePerHour{ 0 };
int hoursWorked{ 0 };
// Print the header
std::cout << header << '\n';
// Read all lines in a loop
while (infile >> employeeNumber >> name >> ratePerHour >> hoursWorked)
{
// calculate the result
const int salary{ ratePerHour * hoursWorked };
// Print table
std::cout << std::left << std::setw(16) << employeeNumber << std::setw(16) << name <<
std::setw(16) << ratePerHour << std::setw(16) << hoursWorked <<
" Salary --> " << salary << '\n';
}
}
return 0;
}
Then, since you are programmin in C++. Use Objects. Objects group related things together and defines methods to operate on the data. So you can define a class and with that a new data type. And becuase the inserter and extractor operator do not exist for this user specific type, you need to create them.
In your main, you can read the complete file in a simpel statement. Then calculate the result and the print it.
See:
#include <iostream>
#include <vector>
#include <string>
#include <iterator>
#include <algorithm>
#include <fstream>
#include <iomanip>
class Payroll
{
public:
Payroll() {}
void calculate() { salary = ratePerHour * hoursWorked; }
friend std::istream& operator >> (std::istream& is, Payroll& p) {
return is >> p.employeeNumber >> p.name >> p.ratePerHour >> p.hoursWorked;
}
friend std::ostream& operator << (std::ostream& os, const Payroll& p) {
return os << std::left << std::setw(16) << p.employeeNumber << std::setw(16) << p.name <<
std::setw(16) << p.ratePerHour << std::setw(16) << p.hoursWorked << std::setw(16) << p.salary;
}
private:
int employeeNumber{ 0 };
std::string name{};
int ratePerHour{ 0 };
int hoursWorked{ 0 };
int salary{ 0 };
};
int main()
{
// Define variable and automatically open it.
// Will be closed by destructor, when infile goes out of scope
std::ifstream infile{ "r:\\assignment.txt" };
// If the file is open ( !operator of ifstream is overlaoded )
if (infile)
{
// Read the header line
std::string header{};
std::getline(infile, header);
// Define a vector of Payroll. Use range the constructor of the vector to read all data from file
std::vector<Payroll> payroll{ std::istream_iterator<Payroll>(infile), std::istream_iterator<Payroll>() };
// For each payroll element in the vector of payrolls: Calculate the salary
std::for_each(payroll.begin(), payroll.end(), [](Payroll & p) {p.calculate(); });
// Output Result:
std::cout << header << " " << "Salary\n";
std::copy(payroll.begin(), payroll.end(), std::ostream_iterator<Payroll>(std::cout, "\n"));
}
return 0;
}
Take your time and try to understand line by line . . .
I can't get this code to output the file info. How would I use ostream overloading to output this? Or do I have to do it some other way? I can't figure it out.
Which C++ sorting algorithm would be the best to use to sort the info ascending order?
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <stdlib.h> // needed to use atoi function to convert strings to integer
using namespace std;
struct Employees
{
string employeeName;
string employeeID;
int rate;
int hours;
};
istream& operator >> (istream& is, Employees& payroll)
{
char payrollStuff[256];
int pay = atoi(payrollStuff); // use atoi function to convert string to int
is.getline(payrollStuff, sizeof(payrollStuff));
payroll.employeeName = payrollStuff;
is.getline(payrollStuff, sizeof(payrollStuff));
payroll.employeeID = payrollStuff;
is.getline(payrollStuff, sizeof(payrollStuff));
payroll.rate = atoi(payrollStuff);
is.getline(payrollStuff, sizeof(payrollStuff));
payroll.hours = atoi(payrollStuff);
return is;
};
int main()
{
const int SIZE = 5; // declare a constant
Employees payroll_size[5];
ifstream myFile;
myFile.open("Project3.dat");
if(myFile.fail()) //is it ok?
{
cerr << "Input file did not open please check it" << endl;
}
else
for (int i=0; i< 5; i++)
{
myFile >> payroll_size[i];
}
myFile.close();
return 0;
}
Just overload the operator in the same way you did for the >>. For example:
ostream& operator<<(ostream& os, Employees& payroll)
{
os << payroll.employeeName << " " << payroll.employeeID << " " << payroll.rate << " " << payroll.hours << "\n";
return os;
}
Then, in a loop, you can just iterate over the array and print out each of the Employees using <<.
On a side note, if you are checking if the file opened, it is better to use the dedicated function std::ifstream::is_open.
For sorting your entries, it is best that you use std::sort, with a custom predicate for whatever criteria you want to sort with. As an example, if you wanted to sort based on the name of the Employee in alphabetical order, you would use the following command:
sort(payroll_size, payroll_size + 5, [](const Employee& a, const Employee& b) { return a.employeeName < b. employeeName; });