Ifstream not retrieving data using array in C++ - c++

I've been trying to read data from employee-info.txt using ifstream and storing it in an array, but it did not read anything.
The main goal of my code is, every time that it was able to read a value in employee-info.txt, It will loop and the integer variable valueChecker will increment by one. After the loop is done, the value of valueChecker will be returned in order to determine how many strings are retrieved from employee-info.txt. Based on the contents of employee-info.txt, it should return an int of 8, but it is only returning an int of 0, which is the initialized value.
I also checked through debugger and the record array did not read anything from the file. I already checked the address of the file and it is correct.
Here is the code in Employee.h:
#pragma once
#include<string>
#include<iostream>
class Employee
{
public:
struct EmployeeRecord {
static const int recordSize = 100;
static const int fieldSize = 4;
std::string record[recordSize][fieldSize];
};
public:
Employee();
~Employee();
int employeeDataChecker();
void employeeWriteData();
void employeeDisplayData();
EmployeeRecord& employeeReturnRecordArray();
private:
EmployeeRecord emp_record;
};
Employee.cpp:
#include "Employee.h"
#include <string>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
int Employee::employeeDataChecker()
{
//Check if there are data in the employee-info.txt
EmployeeRecord emp;
int valueChecker = 0;
std::ifstream inFile;
inFile.open("C:\\Users\\RJ\\Desktop\\employee-info.txt");
for (int index = 0; index < emp.recordSize; index++) {
for (int index2 = 0; index2 < emp.fieldSize; index2++) {
while (inFile >> emp.record[index][index2]) {
valueChecker++;
}
}
}
inFile.close();
return valueChecker;
}
employee-info.txt:
ID Firstname Lastname Sales
1 Joe Satriani 500000.00

Yes, first, you have to check if file is correctly opened (i.e. inFile.is_open()).
Then, forget iteration on fields and try to do something like this:
int id;
char firstname[64] = { 0 };
char lastname[64] = { 0 };
float sales;
inFile >> id;
inFile.get(firstname, 64, ' ');
inFile.get(lastname, 64, ' ');
inFile >> sales;
On failure, [inFile >>] operator could return false and then it wont increment valueChecker.

Related

Read from the file from different functions

I'm trying to read from the same file from another function but it doesn't work.
I guess the problem is that I'm trying to read from ifstream &input but I don't know the other way to implement that
#include <iostream>
#include <fstream>
using namespace std;
class Student{
public:
char name[40]; // i cant use string
int age;
void Input(ifstream &input)
{
input.getline(name, 40);
input >> age;
}
};
void Read(Student *students, int &numberOfStudents)
{
ifstream input("test.txt");
input >> numberOfStudents;
students = new Student[numberOfStudents];
for (int i = 0; i < numberOfStudents; ++i)
students[i].Input(input);
input.close();
}
int main()
{
int size = 0;
Student *students = NULL;
Read(students, size);
for (int i = 0; i < size; ++i)
cout << students[i].name << endl << students[i].age << endl;
return 0;
}
I made my input file
3
1
2
3
4
5
6
(if the program was working correctly i should've get 1 - name age - 2 etc)
but what i got is no names with ages = 1 2 3 respectively
The program does not work because you define:
void Read(Student *students, int &numberOfStudents)
And then
int size = 0;
Student *students = NULL;
Read(students, size);
The students pointer is passed-by value so Read() can not change the memory address outside the function.
To fix this simply pass the the pointer by-reference:
void Read(Student *& students, int &numberOfStudents)
Lastly as I commented you need to account white space e.g. '\n' line ending
In the file when using >> operator to extract data:
void Input(ifstream &input)
{
input.getline(name, 40);
input >> age;
input.ignore(1);
}
Same for reading the number of students in the file.

Reading in input to construct an object

I am trying to read a string line for line down a .txt file in order to initiate an array of objects using a constructor that takes a string.
The text file is written like
TransAm
Mustang
Corvette
I feel like my loop is not iterating the information I want to be set correctly. Is there an easy way of accomplishing this?
main.cc
#include <string>
#include <iostream>
#include "Car.cc"
#include <fstream>
using namespace std;
int main()
{
Car cars[3];
string STRING;
ifstream infile;
infile.open("cars.txt");
// THIS IS HOW IT'S ACHIEVED USING FOR-LOOP - Sam
for(int i = 0; i<3 && infile;++i){
getline(infile,STRING);
cars[i].setName(STRING);
}
/* THIS IS WHAT I HAD
while(!infile)
{
getline(infile,STRING);
for(int i = 0; i<sizeof(cars);i++){
cars[i].setName(STRING);
}
}
*/
infile.close();
for(int j = 0;j<sizeof(cars);j++){
cars[j].print();
}
}
Car.h
#include <string>
using namespace std;
class Car{
public:
Car();
Car(string);
string getName();
void setName(string);
void print();
private:
string name;
};
Car.cc
#include <string>
#include "Car.h"
using namespace std;
Car::Car()
{
}
Car::Car(string s)
{
setName(s);
}
void Car::setName(string s)
{
name = s;
}
string Car::getName()
{
return name;
}
void Car::print()
{
cout << name;
}
These points need to be corrected:
while (!infile) prevents you from entering the loop.
You don't need two loops.
You can modify your loop like this:
for (int i = 0; i < sizeof(cars) && getline(infile, STRING); ++i)
cars[i].setName(STRING);
Or like this:
for (int i = 0; i < sizeof(cars) && infile; ++i) {
getline(infile, STRING);
cars[i].setName(STRING);
}
Your loop does at the moment nothing if the file is correctly opened. It will only enter if the call to open was unsuccessful.
Change your loop to either
while (getline(infile,STRING))
{
//...
}
or
while (infile)
{
//...
}
As it's been said, "Change while(!infile) to while(getline(infile,STRING))" but do not forget to remove the getline(infile,STRING); afterwards.

Reading data into a struct array from a file

I have an input file that looks like this
1 0 3
2 11 5
3 15 1
4 16 11
and a structure that looks like this
struct numb {
int numb1;
int numb2;
int numb3;
}
and I need to create an array of the struct so that each element of the array holds all three numbers. So
numbArray[0].numb1 == 1
numbArray[0].numb2 == 0
numbArray[0].numb3 == 3
numbArray[1].numb1 == 2
numbArray[1].numb2 == 11
and so on. I've gotten the hang of opening and closing files, finding how many lines there are in a file, and reading a single line from a file, but I do not know how to store individual elements from a line.
My program looks like this so far:
#include <iostream>
#include <fstream>
#include <string>
int main(int argc, char* argv[])
{
ifstream inFile(argv[1]);
int fileLength = 0;
std::string line;
while(std::getline(inFile, line))
{
++fileLength;
}
struct numb {
int numb1;
int numb2;
int numb3;
}
if(inFile.is_open())
{
for(unsigned i = 0; i <= fileLength; i++)
{
//What to do here?
}
}
}
Use getline when you don't have regular structure to the input and need to handle variation between lines. When your input file has regular structure (in this case, there are always three values per line), then simply use the stream extraction operators directly:
#include <iostream>
#include <vector>
struct group
{
int n1;
int n2;
int n3;
};
int main()
{
std::vector<group> groups;
while (std::cin)
{
group line;
line.n1 << std::cin;
line.n2 << std::cin;
line.n3 << std::cin;
groups.push_back(group);
}
}
Express your ideas directly in code as much as possible.
Note I've written the code assuming that the file is in the proper form. If there are too many or too few values per line, then the above code will be confused. However, it is best to code the simplest thing that could possibly work and worry about complexity when you need it. In your example you stated that the input file was well-formed, so there's no need to overcomplicate things.
I recommend using a std::stringstream for this:
#include <iostream>
#include <sstream>
#include <string>
#include <stdio.h>
#include <vector>
struct numb {
int numb1;
int numb2;
int numb3;
};
void populate(std::vector<numb>& my_numbs, std::string line) {
std::stringstream ss(line);
numb my_numb;
ss >> my_numb.numb1 >> my_numb.numb2 >> my_numb.numb3;
my_numbs.push_back(my_numb);
}
void output(const numb my_numbs) {
printf("%d %d %d\n", my_numbs.numb1, my_numbs.numb2, my_numbs.numb3);
}
int main(int argc, char* argv[]) {
ifstream inFile(argv[1]);
std::string line;
std::vector<numb> my_vect;
while(std::getline(inFile, line)) {
populate(my_vect, line);
}
for(size_t i = 0; i < my_vect.size(); ++i) {
std::cout << "my_vect[" << i << "]:";
output(my_vect[i]);
}
return 0;
}
std::stringstreams allow you to parse out data types from std::strings, you you just need to parse out 3 ints, which you can use with your struct. You then push the struct into your vector.
Here's the working ideone taking input from stdin.
You should probably be able to do something like this:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
int main(int argc, char* argv[])
{
ifstream inFile(argv[1]);
int fileLength = 0;
std::string line;
struct numb {
int numb1;
int numb2;
int numb3;
};
vector<vector<int>> sets;
int n1, n2, n3;
while (std::cin >> n1)
{
cin >> n2;
cin >> n3;
vector<int> vec;
vec.push_back(n1);
vec.push_back(n2);
vec.push_back(n3);
sets.push_back(vec);
}
numb * numbSet = new numb[sets.size()];
//Since the vectors data is continuous in memory just as the array of structs are
//you can just copy the data directly
for (int i = 0; i < sets.size(); i++)
{
std::memcpy(&numbSet[i], &sets[i][0], sizeof(numb));
}
}

How do I sort data from file by member of a struct? C++

Here I have a program that reads in some employee data from a file and stores them in an array of structs. What I am trying to do with the "sort_by_age" function is to sort this data based on date of birth to where the data is listed from oldest employee to youngest employee.The "read_file" function works fine, and the program compiles fine, but the output is incorrect, the program doesnt sort the data properly as i would like. Any help would be greatly appreciated.
Heres a few lines from the file to give an idea of the format
114680858 19670607 Matilda Vincent MI
114930037 19471024 Desdemona Hanover ID
115550206 19790110 Xanadu Perlman ND
116520629 19630921 Alexander Hall SD
so for example if this was all the lines in the file(its not), i want it to sort Desdemona's info first, then alexander's, then, matilda's, then xanadu's.
#include<string>
#include<iostream>
#include<fstream>
using namespace std;
struct employees // employee data
{
int ss_number;//social security
int dob;//date of birth YYYY/MM/DD Ex.) 19870314=1987/03/14
string f_name;
string l_name;
string state; //state of residence };
void read_file()//read file into array of 1000 structs
{
ifstream data("/home/www/class/een118/labs/database1.txt");
employees array[100]
if(!data.fail())
{
int i;
for(int i=0;i<100;i++)
{
data>>array[i].ss_number
>>array[i].dob
>>array[i].f_name
>>array[i].l_name
>>array[i].state;
}
for(int i=0;i<100;i++)
{
cout<<array[i].ss_number>>" "<<array[i].dob>>" "<<array[i].f_name>>" "<<
array[i].l_name>>" "<<array[i].state;
}}}
void print_person(employees e)
{
cout<<e.ss_number>>" "<<e.dob>>" "<<e.f_name>>" "<<e.l_name>>" "<<e.state;
}
void sort_by_age(employees array[])
{
employees temp;
for(int i=0;i<100;i++)
{
for(int j=i+1;j<100;j++)
{
if(array[j].dob<array[i].dob)
{
temp=array[i];
array[i]=array[j];
array[j]=temp;}
print_person(array[j]);
cout<<"\n";}}}
int main()
{
employees array[100];
read_file(array);
sort_by_age(array);
}
Use std::sort, preferably with a lambda, for example.
#include <string>
#include <iostream>
#include <fstream>
#include <algorithm>
using namespace std;
struct employee {
int social_security_id;
int date_of_birth;
string first_name;
string last_name;
string state;
};
// parses and returns a vector of employees from the given stream.
std::vector<employee> parse_employees(ifstream ifs)
{
std::string str;
std::vector<employee> v;
while (!ifs.eof()) {
employee e;
ifs >> e.social_security_id >> e.date_of_birth >> e.first_name >> e.last_name >> e.state;
v.push_back(e);
}
return v;
}
int main(int argc, char* argv[])
{
ifstream ifs("/home/www/class/een118/labs/database1.txt");
auto employees = parse_employees(ifs);
std::sort( std::begin(employees), std::end(employees),
[]( const employees &a, const employees &b )
{
return ( a.date_of_birth > b.date_of_birth );
});
for (auto e : v) {
cout << e.social_security_id << e.date_of_birth << e.first_name << e.last_name << endl;
}
}

How to correct a segmentation fault?

I keep getting an error Segmentation fault (core dumped), so I ran valgrind. It is my first time using it, so not sure what to do to get my code working. I've tried changing it, but it still says core dumped, or I receive more errors than I had before. I did try debugging the code with gdb, but the debugger was not working properly.
and corresponding product.h
#ifndef GS_PRODUCT
#define GS_PRODUCT
#include <iostream>
#include <string>
using namespace std;
class Product
{
private:
int plu_code;
string name;
double price;
bool by_weight;
double inventory;
public:
Product(int p_code = 0, string p_name = "", bool p_by_weight = true, double p_price = 0.0, double p_inv = 0.0);
bool sold_by_weight(void);
double compute_cost(double weight_or_unit);
string get_name(void);
int get_plu_code(void);
double get_price(void);
double get_inventory(void);
};
#endif
This is my product.cpp:41
#include <iostream>
#include <string>
#include "product.h"
using namespace std;
Product::Product(int p_code, string p_name, bool p_by_weight, double p_price, double p_inv)
{
plu_code = p_code;
name = p_name;
by_weight = p_by_weight;
price = p_price;
inventory = p_inv;
}
bool Product::sold_by_weight(void)
{
return by_weight;
}
double Product::compute_cost(double weight_or_units)
{
inventory -= weight_or_units;
return weight_or_units * price;
}
string Product::get_name(void) {
return name;
}
int Product::get_plu_code(void) {
return plu_code;
}
double Product::get_price(void) {
return price;
}
double Product::get_inventory(void) {
return inventory;
}
This is my main program store
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <sstream>
#include "product.h"
#include "Tokenizer.h"
#include "LookupTable.h"
using namespace std;
LookupTable<Product *> table;
int numProducts = 0;
void checkout()
{
}
int main()
{
int plu;
string name;
int weight;
double inv;
double price;
table.addRange(0, 9999);
table.addRange(90000, 99999);
// std::string line;
//Input file
ifstream infile("inventory.csv");
if(infile.fail())
perror("Could not open file ");
stringstream ss;
while(infile.good())
{
string line = "";
//read a product info from file
getline(infile, line);
Tokenizer tok(line, ",");
ss<<line;
//string token = tok.next();
ss >> plu >> name >> weight >> price >>inv;
table[plu] = new Product(plu, name,weight, price,inv);
numProducts++;
}
infile.close();
checkout();
ofstream outfile;
outfile.open("output.csv");
for(int i=0; i< numProducts; i++)
{
outfile<< table[i]-> get_plu_code() << "" << table[i]->get_name()<<""<<table[i]->sold_by_weight() <<""<<table[i]->get_price() <<""<<table[i]->get_inventory();
}
outfile.close();
return 0;
}
The meaning of a segmentation fault is that you tried to access a page which doesn't have the permissions (normally read/write permission but possibly also executable permission) needed for the operation. That is, the system tells you that you tried to access something which isn't really there or which is inaccessible.
There are many typical problems eventually resulting in segmentation faults. Here are a few of those:
An uninitialized pointer is dereferenced.
A null pointer is dereferenced.
An array is accessed outside its boundaries, thus accessing random memory as if it were an array element.
A released object is being used as if it is live, e.g., an object after being deleted or an object which was on the stack.
... and many more similar stuff.
To get help with the actual segmentation fault you have, you'll need to provide a short but complete example exhibiting the problem. Quoting a few lines which you think are related to the problem are generally rather unlikely to actually contain the actual problem.
You don't appear to have any value inventory to return from Product::get_inventory(). I would think that either this wouldn't compile, or you have some code that you haven't shown that is relevant. Most likely, the latter is the case, and the variable inventory is not yet initialized at the time that it is returned.