Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
my build is totally successful here, yet not outputting to my text file, I know I asked a question a few days ago about this program, and I've since changed it. What am I doing wrong now?
Thanks in advance guys.
I'm trying to input from an employeesIn.txt file and create an employeesOut.txt file made of employee structures.
Here's my text file.
123,John,Brown,125 Prarie Street,Staunton,IL,62088
124,Matt,Larson,126 Hudson Road,Edwardsville,IL,62025
125,Joe,Baratta,1542 Elizabeth Road,Highland,IL,62088
126,Kristin,Killebrew,123 Prewitt Drive,Alton,IL,62026
127,Tyrone,Meyer,street,999 Orchard Lane,Livingston,62088
The output should look like
Employee Record: 123
Name: John Brown
Home Address: 125 Prarie Street
Staunton, IL 62088
Employee Record: 124
Name Matt Larson
Home Address:.... and so on
Here's my code.
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
using namespace std;
struct Person {
string first;
string last;
};
struct Address {
string street;
string city;
string state;
string zipcode;
};
struct Employee {
Person name;
Address homeAddress;
int eid;
};
int readEmployee(istream& in, Employee eArray[]);
void displayEmployee(ostream& out,Employee eArray[], int EmployeePopulation);
const int arr=50;
Employee eArray[arr];
ifstream fin;
ofstream fout;
int main(int argc, const char * argv[])
{
fin.open("employeesIn.txt");
if (!fin.is_open()) {
cerr << "Error opening employeesIn.txt for reading." << endl;
exit(1);
}
fout.open("employeesOut.txt");
if (!fout.is_open()) {
cerr << "Error opening employeesOut.txt for writing." << endl;
exit(1);
}
int tingle = readEmployee(fin, eArray);
fin.close();
displayEmployee(fout, eArray, tingle);
fout.close();
exit(0);
}
int readEmployee(istream& in, Employee eArray[])
{
string eidText;
string line;
getline(in, line);
int EmployeePopulation = 0;
while (!in.eof()) {
getline(in, eidText, ',');
eArray[EmployeePopulation].eid = stoi(eidText);
getline(in, eArray[EmployeePopulation].name.first, ',');
getline(in, eArray[EmployeePopulation].name.last, ',');
getline(in, eArray[EmployeePopulation].homeAddress.street, ',');
getline(in, eArray[EmployeePopulation].homeAddress.city, ',');
getline(in, eArray[EmployeePopulation].homeAddress.state, ',');
getline(in, eArray[EmployeePopulation].homeAddress.zipcode);
EmployeePopulation++;
}
return EmployeePopulation;
}
void displayEmployee(ostream& out, Employee eArray[], int EmployeePopulation)
{
for (int i = 0; i <= EmployeePopulation - 1; i++) {
out << "Employee Record: " << eArray[i].eid
<< endl
<< "Name: " << eArray[i].name.first << " " << eArray[i].name.last
<< endl
<< "Home address: " << eArray[i].homeAddress.street
<< endl
<< eArray[i].homeAddress.city << ", " << eArray[i].homeAddress.state << " " << eArray[i].homeAddress.zipcode
<< endl
<< endl;
}
}
Two things:
You should use return 0 rather than exit(0) at the end of main.
Checking for eof after you have performed several reads and tried to convert the data is wrong. You need to check for failure of the reads themselves.
This corrects the eof issue. The program was crashing for me because stoi threw an exception when the read failed.
int readEmployee(istream& in, Employee eArray[])
{
string eidText;
string line;
//This discards the first line. Incorrect for the test data you supplied.
getline(in, line);
int EmployeePopulation = 0;
//Check for errors while reading, not eof after the fact.
//This was crashing because stoi failed when no data was
//read due to eof being true after the loop check.
while( getline(in, eidText, ',') &&
getline(in, eArray[EmployeePopulation].name.first, ',') &&
getline(in, eArray[EmployeePopulation].name.last, ',') &&
getline(in, eArray[EmployeePopulation].homeAddress.street, ',') &&
getline(in, eArray[EmployeePopulation].homeAddress.city, ',') &&
getline(in, eArray[EmployeePopulation].homeAddress.state, ',') &&
getline(in, eArray[EmployeePopulation].homeAddress.zipcode))
{
eArray[EmployeePopulation].eid = stoi(eidText);
EmployeePopulation++;
}
return EmployeePopulation;
}
You would have fewer problems if you used a vector of Employee.
You could pass it by reference to the functions.
The functions could get the number of employees by using std::vector::size().
The std::vector automatically expands when using the push_back method.
If you created input and output methods for your classes, you wouldn't have to violate encapsulation:
class Person // using class to support privacy and encapsulation
{
std::string first_name;
std::string last_name;
public:
friend std::istream& operator>>(std::istream& inp, Person& p);
friend std::ostream& operator<<(std::ostream& out, const Person& p);
};
std::istream& operator>>(std::istream& inp, Person& p)
{
std::getline(inp, p.first_name, ',');
std::getline(inp, p.last_name, ',');
}
std:ostream& operator<<(std::ostream& out, const Peron& p)
{
out << "Name: ";
out << p.first_name;
out << " ";
out << p.last_name;
}
class Employee
{
Person name;
Address addr;
public:
friend std::istream& operator>>(std::istream& inp, Employee& e);
};
std::istream& operator>>(std::istream& inp, Employee& e)
{
inp >> name;
inp >> addr;
};
The missing formatted input and output are left as an exercise for the reader.
In your readEmployee function, you passed isstream& in.I suppose you should be checking for while (!in.eof()) ans not while (!fin.eof()).
And your getline(fin, line); should be getline(in, line); too.
Related
I'm creating a program that reads the author, title, and number of volumes from a file and prints out labels,
(ex.
Adams
A Complete History of the World
Volume 1 of 10
Adams
A Complete History of the World
Volume 2 of 10 etc.)
To make it read properly and not infinitely loop, I had to change all of my variable to string. However, for future reference to the volume number, I need it to be int so I can compare the amount.
My ideas for furthering the code with a do-while loop are commented in to show why I'd like vnum to have int value.
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main()
{
ifstream fin;
string author;
string title;
string vnum;
int counter=1;
fin.open("publish.txt", ios::in);
while (!fin.eof())
{
getline(fin, author);
getline(fin, title);
getline(fin, vnum);
//do
//{
cout << author << endl;
cout << title << endl;
cout << "Volume " << counter << " of " << vnum << endl;
cout << endl;
//counter++;
//} while(counter < vnum);
}
fin.close();
return 0;
}
File I'm reading from:
Adams
A Complete History of the World
10
Samuels
My Life of Crime
2
Baum
Wizard Stories
6
First of all, avoid use of
while (!fin.eof())
See Why is “while ( !feof (file) )” always wrong? to understand the problems it would cause.
Coming to your task, I would suggest:
Create a struct to hold the data.
Add a function to read all the members of the struct from a std::istream.
Add a function to write all the members of the struct to a std::ostream.
Simplify main to use the above.
Here's what I suggest:
struct Book
{
std::string author;
std::string title;
int volume;
};
std::istream& operator>>(std::istream& in, Book& book);
std::ostream& operator<<(std::ostream& out, Book const& book);
That will help simplify main to:
int main()
{
ifstream fin;
Book book;
// Not sure why you would need this anymore.
int counter=1;
fin.open("publish.txt", ios::in);
while ( fin >> book )
{
cout << book;
++counter;
}
return 0;
}
The functions to read and write a Book can be:
std::istream& operator>>(std::istream& in, Book& book)
{
// Read the author
getline(in, book.author);
// Read the title
getline(in. book.title);
// Read the volume
in >> book.volume;
// Ignore rest of the line.
in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
return in;
}
std::ostream& operator<<(std::ostream& out, Book const& book)
{
out << book.author << std::endl;
out << book.title << std::endl;
out << book.volume << std::endl;
return out;
}
I'm trying to take the profile info(username, email, etc.) from one directory and put it in another. I've been debugging the code for this program, and while there are no errors, the program won't run, saying that the program "has stopped working". I have already looked on this website and others for any possible answers, and found none.
#include <string>
#include <cstring>
#include <iostream>
#include <istream>
#include <ostream>
#include <fstream>
#include <iomanip>
#include <filesystem>
using namespace std;
class path{
public:
string parent_directory;
string root_directory;
};
class Data{
public:
string userName;
string nickName;
string fName;
string arena_FName;
string lName;
string arena_LName;
string email;
string arenaEmail;
friend std::istream& operator>>(std::istream& input, Data& d);
};
std::istream& operator>>(std::istream& input, Data& d){
std::getline(input, d.userName);
std::getline(input, d.nickName);
//...
std::getline(input, d.arenaEmail);
return input;
}
int main(){
ifstream myfile("myfunk.txt", ios::in);
ofstream arena("arena.txt");
myfile.open("myfunk.txt", ios::in);
if(myfile){
cout << "Input file open." << endl;
}
arena.open("arena.txt", ios::out | ios::app);
if(arena){
cout << "Output file open." << endl;
}
cout << "file opening test: success" << endl;
int x = 0;
int y = 4101; //Total number of users in the directory.
int z = 0; //For inputting the required lines of info for each profile.
int profile = 0;
bool valid = false;
string role;
//string arenaRole;
bool post = false;
string line;
string p = "This PC/..."; //Path to the folder of the individual pictures.
//myVar.save("...");
string p = "...";
path path1;
path root_directory;
path parent_directory;
//bool is_directory(const std::filesystem::path& p, std::error_code& ec) noexcept; //Checks if current location is a directory.
//bool postPic;
const unsigned int MAXIMUM_DATA = 4100u;
Data database[MAXIMUM_DATA];
cout << "All variables but the filesystem have been accepted! Please install this program on the network." << endl;
while(x < y){
cout << "Primary loop functioning" << endl;
if(post = true){
getline(myfile, line); //Grab and read next line.
myfile >> line;
line = userName[x];
arena << "Username: " << userName[x] << "\n";
z++;
getline(myfile, line);
myfile >> line;
line = role[x];
arena << "Role: " << role[x] << "\n";
z++;
getline(myfile, line);
line = nickName[x];
myfile >> nickName[x];
arena << "nickname: " << nickName[x] << "\n";
z++;
getline(myfile, line);
line = fName[x];
myfile >> fName;
arena << "First Name: " << fName[x] << "\n";
z++;
getline(myfile, line);
line = lName[x];
myfile >> lName;
arena << "Last Name: " << lName[x] << "\n";
z++;
getline(myfile, line);
myfile >> line;
line = email[x];
arena << "Email: " << email[x] << "\n";
getline(myfile, line);
z = 0; //Next profile...
}
int data;
while(myfile >> data){
if(nickName[x] = NULL){
myfile >> "<Error> Some required information is missing! Contact user! </Error> /n";
valid = false;
post = false;
x++;
}
if(email[x] != NULL){
std::string str("#");
std::string str2(".com");
std::string str3(".net");
std::string str4(".edu");
if(std::size_t found = email[x].find(str) & (std::size_t found = email[x].find(str2) || std::size_t found = email[x].find(str3) || std::size_t found = email[x].find(str4)){
valid = true;
if(valid = true){
post = true;
}
}
else{
valid = false;
post = false;
x++;
}
}
}
}
}
}
x++;
}
//x++;
myfile.close(); //Closes the file in the directory.
arena.close(); //Closes the file in Arena.
return 0;
}
Let's rework your code.
First, let's create a data structure for the data:
class Data
{
public:
string userName;
string nickName;
string fName;
string arena_FName;
string lName;
string arena_LName;
string email;
string arenaEmail;
};
If you need an array for the data, it would be declared as:
const unsigned int MAXIMUM_DATA = 4100u;
Data database[MAXIMUM_DATA];
Next, let's overload the extraction operator>> to make reading easier:
class Data
{
public:
//...
friend std::istream& operator>>(std::istream& input, Data& d);
};
std::istream& operator>>(std::istream& input, Data& d)
{
std::getline(input, d.userName);
std::getline(input, d.nickName);
//...
std::getline(input, d.arenaEmail);
return input;
}
This simplifies your input loop to:
std::vector<Data> database;
Data d;
while (my_file >> d)
{
database.push_back(d);
}
You can query the amount of data read in by using the std::vector::size() method, i.e. database.size().
Also, you don't need a separate structure for a file path. A simple std::string will suffice. I recommend using forward slash, '/', because it is recognized by both Windows and *nix operating systems and won't be interpreted as an escape character.
I thought I had this completely worked out, but it isn't actually writing anything to the file. It is opening the employeesOut.txt file but not writing anything. Any guesses? I'm getting the error
Here is the input file as requested.
123,John,Brown,125 Prarie Street,Staunton,IL,62088
124,Matt,Larson,126 Hudson Road,Edwardsville,IL,62025
125,Joe,Baratta,1542 Elizabeth Road,Highland,IL,62088
126,Kristin,Killebrew,123 Prewitt Drive,Alton,IL,62026
127,Tyrone,Meyer,street,999 Orchard Lane,Livingston,62088
libc++abi.dylib: terminating with uncaught exception of type std::invalid_argument: stoi: no conversion
(lldb)
I believe the error is within my main.cpp, so here that is.
#include <iostream>
#include <string>
#include <fstream>
#include "Employee.h"
using namespace std;
bool openFileForReading(ifstream& fin, const string& filename);
bool openFileForWriting(ofstream& fout, const string& filename);
int readFromFile(ifstream& in, Employee empArray[]);
void writeToFile(ofstream& out, const Employee empArray[], const int numberofEmployees);
int main(){
ifstream fin;
ofstream fout;
if(!openFileForReading(fin, "employeesIn.txt")) {
cerr << "Error opening employeesIn.txt for reading." << endl;
exit(1);
}
if(!openFileForWriting(fout, "employeesOut.txt")) {
cerr << "Error opeing employeesOut.txt for writing." << endl;
exit(1);
}
Employee employeeArray[50];
int employeeCount = readFromFile(fin, employeeArray);
fin.close();
writeToFile(fout, employeeArray, employeeCount);
fout.close();
cout << "Program successful." << endl << endl;
return 0;
}
bool openFileForReading(ifstream& fin, const string& filename) {
fin.open("employeesIn.txt");
return (fin.is_open());
}
bool openFileForWriting(ofstream& fout, const string& filename) {
fout.open("employeesOut.txt");
return (fout.is_open());
}
int readFromFile(ifstream& in, Employee empArray[]) {
int temp = 0;
string eidText;
string first;
string last;
string street;
string city;
string state;
string zipcode;
while(!in.eof()) {
getline(in, eidText, ',');
getline(in, first, ',');
getline(in, last, ',');
getline(in, street, ',');
getline(in, city, ',');
getline(in, state, ',');
getline(in, zipcode, ',');
empArray[temp].setEid(stoi(eidText));
empArray[temp].setName(first, last);
empArray[temp].setAddress(street, city, state, zipcode);
temp++;
}
return temp;
}
void writeToFile(ofstream& out, const Employee empArray[], const int numberOfEmployees) {
for (int i = 0; i < numberOfEmployees; i++){
out << "Employee Record: " << empArray[i].getEid()
<< endl
<< "Name: " << empArray[i].getName()
<< endl
<< "Home Address: " << empArray[i].getAddress()
<< endl
<< endl;
}
}
Your initial problem is solved by changing your getline(in, zipcode, ','); line to getline(in, zipcode, '\n');, since this will make getline end on the linebreak character. The error is generated when stoi is given 'Matt' as an argument.
However, your readFromFile function is receiving a copy of your array, and so the changes it makes aren't moved back into your main() function (since you're returning the count, not the array).
Since passing an array of references is messy, try instead using a std::vector (after #includeing <vector>) to group your individual employees. If Employee.H specifies a parameter-less constructor or no constructor (and you have a default constructor from your compiler), then
std::vector<Employee> employeeVector;
void readFromFile(ifstream& in, std::vector<Employee> &empVec);
void readFromFile(ifstream& in, std::vector<Employee> &empVec) {
// int temp = 0; unneeded.
string eidText;
...
string zipcode;
while(!in.eof()) {
getline(in, eidText, ',');
...
getline(in, zipcode, '\n');
Employee tempEmp();
tempEmp.setEid(stoi(eidText));
...
empVec.push_back(tempEmp);
// temp++; no longer need this
}
}
might be a better option. Even if the constructor is horribly complicated, it's still likely this would be simpler than arrays of references (you'd have to change the Employee tempEmp(); line though. Incidentally, if this complains and won't compile, I probably hit the MVP error - remove the ()s and you'll be fine.
Edit:
Since you've been instructed to use an array of Employees, you can choose to return the array, if you wish, or alternatively passing it by pointer should be legal. This would require that you iterate through by moving the pointer along the array in a similar manner to your original code. I've left the vector approach above, since I think it's cleaner, but since you can't use it, you can choose from the two alternatives (return array, pass pointer instead of object). My guess is you're supposed to opt for the pointer, since this now appears to be a homework-style problem.
In that case, you can use
int main() {
...
Employee* empPtr = employeeArray;
...
}
void readFromFile(ifstream& in, Employee* empPtr) {
string eidText;
...
string zipcode;
while(!in.eof()) {
getline(in, eidText, ',');
...
getline(in, zipcode, '\n');
(*empPtr).setEid(stoi(eidText));
...
empPtr++;
}
}
Hi I'm trying to fill in an array of a class object I created. Input is from a text file. The text file has strings and numbers. I got the first set of info in but the rest of the file won't read in, any thoughts would be appreciated!
class mess
{
private:
string name;
float age, weight, height;
public:
void setname(string a) {name=a;}
void setage(float b){age=b;}
//etc.
string getname(){return name;}
float getage(){return age;}
//etc.
}
ifstream input;
input.open("test.txt");
mess people[2]
string str;
float num;
for(inti=0; i<2; i++)
{
getline(input,str,'\n');
people[i].setname(str);
input >> num;
people[i].setage(num);
input >> num;
people[i].setweight(num);
input >> num;
people[i].setheight(num);
}
for(inti=0; i<2; i++)
{
cout << people[i].getname() << endl;
cout << people[i].getage() << endl;
cout << people[i].getweight() << endl;
cout << people[i].getheight() << endl;
}
test.txt
jack
17 150.3 5.10
Amy
18 110.4 5.11
Output:
Jack
17
150.3
5.10
(blank)
0
0
0
The problem here is that when you use the input operator >> it will leave the newline after the last number for the first record. This means that the next getline call will read that newline as an empty line, and then the numbers will fail to read.
There are a couple of ways to solve this. The first is to discard all text in the input until newline after reading the last number in the record. For this you can do e.g.
// All other input in loop
input.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
Read about the ignore function.
Another way is to read the second line, complete, and put it into an std::istringstream and then read out the numbers from it:
// Reading the name...
std::string numbers;
std::getline(input, numbers);
std::istringstream istr(numbers);
istr >> num;
people[i].setage(num);
// ...
Also note that the third argument to std::getline already defaults to a newline, so if you're using it to read lines, then you don't need to provide it.
I suggest you overload operators << and >> in your class:
class mess
{
private:
string name;
float age, weight, height;
public:
void setname(string a) {name=a;}
void setage(float b){age=b;}
//etc.
string getname(){return name;}
float getage(){return age;}
//etc.
friend std::istream& operator>>(std::istream& inp, mess& m);
friend std::ostream& operator<<(std::ostream& out, const mess& m);
}
std::istream& operator>>(std::istream& inp, mess& m)
{
std::getline(inp, m.name);
inp >> m.age;
inp >> m.weight;
inp >> m.height;
return inp;
}
std::ostream& operator<<(std::ostream& out, const mess& m)
{
out << m.name << endl;
out << m.age << endl;
out << m.weight << endl;
out << m.height << endl;
return out;
}
This simplifies your input to:
std::vector<mess> people;
mess p;
while (input_file >> p)
{
people.push_back(p);
}
Your output looks like:
for (unsigned int i = 0; i < people.size(); ++i)
{
cout << people[i];
cout << "\n";
}
I would define the operator<< to write out an object of your class. Then defined the operator>> to read an object of your class. Then you can use std::istream_iterator to read the values directly into the container:
class M
{
private:
string name;
float age;
float weight;
float height;
public:
<STUFF>
friend std::ostream& operator<<(std::ostream& s, M const& data)
{
return s << data.age << " "
<< data.weight << " "
<< data.height << " "
// Put name on the edn because it may contain space.
// So we want to read it off using std::getline
<< data.name << "\n";
}
friend std::istream& operator>>(std::istream& s, M& data)
{
s >> data.age >> data.wight >> data.height;
std::getline(s, data.name);
// Strip leading space (see output operator)
data.name = data.name.substring(1);
return s;
}
};
Then easy to use in most containers.
int main()
{
std::ifstream f("data");
// OK.
// A vector is not actually an array.
// But you can use the same principle with a manual loop.
// as std::istream_iterator is just a normal iterator.
std::vector<M> data(std::istream_iterator<M>(f), std::istream_iterator<M>());
}
I am looking for a way to extract out data from a txt file which data is seperated by row and each column of data is seperaed by |
Here's an example
12|john bravo|123 kings street
15|marry jane|321 kings street
Previously i did it by separating using spaces like this
12 john kingstreet
15 marry kingstreet
But it poses a problem when I add a last name to the names/ add an address with spaces, ex: john bravo
So I decided to separate the column data using |
this is how I extract the data
struct PERSON{
int id;
string name;
string address;
};
//extract
int main(){
PERSON data[2];
ifstream uFile("people.txt");
int i = 0;
while(uFile >> data[i].id >> data[i].name >> data[i].address){
i++;
}
return 0;
}
So how do i extract if the columns are separated by | ??
Use getline() twice:
First, get each line use default seperator (new line); second, for each segment from first step, use '|' as seperator. "stringstream" class may be used to transfer data.
#edward The code below is modified from yours, and I think #P0W58 's answer is better.
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
const int length = 2;
struct PERSON
{
int id;
string name;
string address;
};
//extract
int main()
{
PERSON data[length];
ifstream fin("people.txt");
int i = 0;
while(true)
{
string segment;
if (!getline(fin, segment))
break;
stringstream transporter;
transporter << segment;
string idString;
getline(transporter, idString, '|');
getline(transporter, data[i].name, '|');
getline(transporter, data[i].address, '|');
stringstream idStream;
idStream << idString;
idStream >> data[i].id;
i++;
}
for (i=0; i<length; i++)
cout << data[i].id << '+' << data[i].name << '+'\
<< data[i].address << endl;
return 0;
}
To read into a struct , I'd overload << and then parse the text as mentioned in one of the answer .
Something like this :
#include<sstream>
//...
struct PERSON{
int id;
std::string name;
std::string address;
friend std::istream& operator >>(std::istream& is, PERSON& p)
{
std::string s;
std::getline(is, s); //Read Line, use '\r' if your file is saved on linux
std::stringstream ss(s);
std::getline(ss, s, '|'); //id
p.id = std::atoi(s.c_str());
std::getline(ss, p.name, '|'); // name
std::getline(ss, p.address, '|'); //address
return is ;
}
};
And then you can probably do,
std::ifstream fin("input.txt");
PERSON p1;
while (fin >> p1)
//std::cout << p1.id << p1.name << std::endl ;
You can overload << too
Use boost::tokenizer or find first of like :
// code example
string s = "12|john bravo|123 kings street";
string delimiters = "|";
size_t current;
size_t next = -1;
do
{
current = next + 1;
next = s.find_first_of( delimiters, current );
cout << s.substr( current, next - current ) << endl;
}
while (next != string::npos);