Here is my code for an assignment I have. Whenever I try and compile I get an error for my read function due to something in "ios_base.h" I am not sure what to do and/or if my code does the intended function of taking a file and moving it's elements into a separate file that has the name and average next to each other.
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
using namespace std;
struct Student
{
string fname;
string lname;
double average;
};
int read(ifstream, Student s[]);
void print(ofstream fout, Student s[], int amount);
int main()
{
const int size = 10;
ifstream fin;
ofstream fout;
string inputFile;
string outputFile;
Student s[size];
cout << "Enter input filename: ";
cin >> inputFile;
cout << "Enter output filename: ";
cin >> outputFile;
cout << endl;
fin.open(inputFile.c_str());
fout.open(outputFile.c_str());
read(fin , s);
print(fout, s, read(fin, s));
}
int read(ifstream fin, Student s[])
{
string line;
string firstName;
string lastName;
double score;
double total;
int i=0;
int totalStudents=0;
Student stu;
while(getline(fin, line)){
istringstream sin;
sin.str(line);
while(sin >> firstName >> lastName){
stu.fname = firstName;
stu.lname = lastName;
while(sin >> score){
total *= score;
i++;
}
stu.average = (total/i);
}
s[totalStudents]=stu;
totalStudents++;
}
return totalStudents;
}
void print(ofstream fout, Student s[], int amount)
{
ostringstream sout;
for(int i = 0; i<amount; i++)
{
sout << left << setw(20) << s[i].lname << ", " << s[i].fname;
fout << sout << setprecision(2) << fixed << "= " << s[i].average;
}
}
Stream objects are not copyable. Their copy constructor is deleted. They must be passed by reference, not by value:
int read(ifstream &, Student s[]);
void print(ofstream &fout, Student s[], int amount);
etc...
Sam Varshavchik's answer is correct, but he didn't mention why stream objects don't allow you to copy them.
The issue here is that a stream object owns a buffer, and buffers can't be copied safely.
To take an example, suppose you have data coming in over a network socket and a buffer sitting in front of it, and you copy this buffered reader. If you read from the copy, it will read some indeterminate amount of data and put it into the buffer. This data is now gone from the network socket and only exists in the buffer. Now suppose you read from the copy. Then you'll get some indeterminate amount of data that came after the data you read in the original. Going back and forth in this way, you'd get two "streams" with gaps in them where the other reader was reading the data.
Related
I have a program that uses various structs and functions to read information into a struct from an output file, do something with it, and write to an output file if a condition is met. Everything is working properly, except the function that's supposed to write to the output file isn't doing so. I'm required to have a function that writes to the output file, so doing it in main isn't an option.
edit: The function to write to the output file is at the very bottom.
another edit: I only need information written to the output file if the subscription is expired (so if customer.custInfo.monthsLeft==0).
Here's my code:
#include <iostream>
#include <iomanip>
#include <fstream>
#include <climits>
using namespace std;
struct subscriberName{
string firstName;
string lastName;
int custId;
};
struct address{
string street;
string city;
string state;
int zip_code;
};
struct date{
string month;
int day;
int year;
};
struct renewal_information{
int monthsLeft;
date lastNoticeSent;
};
struct subscriber{
subscriberName custName;
address custAddress;
renewal_information custInfo;
};
void openInFile(ifstream&);
void openOutFile(ofstream&);
subscriber recordIn(ifstream&, subscriber&, address&, date&, int&, int&);
void expired(subscriber&, ofstream&);
int main() {
ifstream inFile;
ofstream outFile;
openInFile(inFile);
openOutFile(outFile);
subscriber customer;
address custAddress;
date custDate;
int currentLine=0, numProcessed=0, numExpired=0;
while (!inFile.eof()){
recordIn(inFile, customer, custAddress, custDate, currentLine, numProcessed);
if (customer.custInfo.monthsLeft==0) {
expired(customer, outFile);
numExpired++;
}
}
cout<<endl<<string(47, '-')<<endl<<"Number of subscribers processed: "<<numProcessed
<<endl<<"The number of expired subscriptions is: " <<numExpired<<endl
<<string(47, '-')<<endl<<endl;
inFile.close();
outFile.close();
return 0;
}
void openInFile(ifstream& inFile){
string inFileName;
do{
cout<<"Enter input file name: ";
cin>>inFileName;
cout<<inFileName<<endl;
inFile.open(inFileName.c_str());
}
while (!inFile);
if (inFile.fail()){
cout<<"input file failed to open\n";
inFile.clear();
} else
cout<<inFileName<<" opened successfully\n";
}
void openOutFile(ofstream&){
string outFileName;
ofstream outFile;
do{
cout<<"Enter output file name: ";
cin>>outFileName;
cout<<outFileName<<endl;
outFile.open(outFileName.c_str());
}
while (!outFile);
if (outFile.fail()){
cout<<"output file failed to open\n";
outFile.clear();
} else
cout<<outFileName<<" opened successfully\n";
}
subscriber recordIn(ifstream& inFile, subscriber& customer, address& custAddress, date& custDate, int& currentLine, int& numProcessed){
inFile.ignore(currentLine, '\n');
getline(inFile, customer.custName.firstName, '\n');
if (inFile.eof()){
return customer;
}
else {
getline(inFile, customer.custName.lastName, '\n');
inFile >> customer.custName.custId;
cout << "==> Processing Customer ID: " << customer.custName.custId << endl;
numProcessed++;
inFile.ignore(INT_MAX, '\n');
getline(inFile, customer.custAddress.street, '\n');
getline(inFile, customer.custAddress.city, '\n');
getline(inFile, customer.custAddress.state, '\n');
inFile >> customer.custAddress.zip_code;
inFile >> customer.custInfo.monthsLeft;
inFile >> customer.custInfo.lastNoticeSent.month;
inFile >> customer.custInfo.lastNoticeSent.day;
inFile >> customer.custInfo.lastNoticeSent.year;
currentLine = currentLine + 11;
}
return customer;
}
void expired(subscriber& customer, ofstream& outFile){
while (customer.custInfo.monthsLeft==0) {
outFile << customer.custName.firstName;
outFile << customer.custName.lastName;
outFile << customer.custName.custId;
outFile << customer.custAddress.street;
outFile << customer.custAddress.city;
outFile << customer.custAddress.state;
outFile << customer.custAddress.zip_code;
outFile << customer.custInfo.monthsLeft;
outFile << customer.custInfo.lastNoticeSent.month;
outFile << customer.custInfo.lastNoticeSent.day;
outFile << customer.custInfo.lastNoticeSent.year;
customer.custInfo.monthsLeft=-1;
outFile.flush();
}
}
In this code
void openOutFile(ofstream&){
string outFileName;
ofstream outFile;
...
}
outFile should be the parameter of openOutFile and not a local variable, otherwise the call to openOutFile(outFile); does not return with an open stream outFile.
The following code is for a project I have to do where I recieve a text file that has a students first and last name followed by his grades. I then have to convert that into an output file that contains his name followed by his average score. The file I recieve has multiple students in it spereated line by line. The output should look relativly like
Rzam, Look = 0.00
Bambi, Lambi = 40.47
Coop, Jason = 27.31
but mine is merely printing garbage such as
0x7fffb08e8698= 0.000x7fffb08e8698= 0.000x7fffb08e8698= 0.000x7fffb08e8698= 0.000x7fffb08e8698= 0.000x7fffb08e8698= 0.000x7fffb08e8698= 0.000x7fffb08e8698= 0.000x7fffb08e8698= 0.000x7fffb08e8698= 0.00
Here is what I have so far:
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
using namespace std;
struct Student
{
string fname;
string lname;
double average;
};
int read(ifstream &fin, Student s[]);
void print(ofstream &fout, Student s[], int amount);
int main()
{
const int size = 10;
ifstream fin;
ofstream fout;
string inputFile;
string outputFile;
Student s[size];
cout << "Enter input filename: ";
cin >> inputFile;
cout << "Enter output filename: ";
cin >> outputFile;
cout << endl;
fin.open(inputFile.c_str());
fout.open(outputFile.c_str());
read(fin , s);
print(fout, s, size);
fin.close();
fout.close();
}
int read(ifstream &fin, Student s[])
{
string line;
string firstName;
string lastName;
double score;
double total;
int i=0;
int totalStudents=0;
Student stu;
while(getline(fin, line)){
istringstream sin;
sin.str(line);
while(sin >> firstName >> lastName){
stu.fname = firstName;
stu.lname = lastName;
while(sin >> score){
total *= score;
i++;
}
stu.average = (total/i);
}
s[totalStudents]=stu;
totalStudents++;
}
return totalStudents;
}
void print(ofstream &fout, Student s[], int amount)
{
ostringstream sout;
for(int i = 0; i<amount; i++)
{
sout << left << setw(20) << s[i].lname << ", " << s[i].fname;
fout << sout << setprecision(2) << fixed << "= " << s[i].average;
}
}
You have a few bugs, which have added up to your issue:
in your print function, you write to a ostringstream and then try to write that to the file stream. Which is fine, but it is printing the address of the ostringstream buffer. So making this change will cause it to print the contents:
fout << sout.str() << setprecision(2) << fixed << "= " << s[i].average;
Note the usage of .str(). Though you don't really need a temporary stream here at all...
You don't place a newline in the output, so it all ends up one line making it hard to read:
so make another change making it look like this:
fout << sout.str() << setprecision(2) << fixed << "= " << s[i].average << '\n';
You need to place the ostringstream sout; inside the loop, so it is reset each time too. Otherwise you will get weirdly compounding output.
You don't use the count of students calculated by your read function! so it always tries to print 10! Do something like this:
int count = read(fin , s);
print(fout, s, count);
If no score is read, I think you'll have a divide by zero. So you should add a check.
You should ensure that no more than size Students are read. Or better yet, just place them in a std::vector and return that from the function. It's simpler and less error prone.
You need to reset i each time you start reading a student, or the later students will get divided by way too much. Each needs to have an independent count.
I don't know if these are the only issues, but certainly it should get you started on the right track :-)
I am making a program keeping track of different persons, which I try to read in from a file. I use a constructor that takes an ifstream file as an argument, and I then try to read in the data from the file. I can read the first line, which is just an int (a unique number for each person), but when I try to go to the next line and getline it, the program hangs. Does anyone know why?
#include <iostream>
#include <fstream>
#include <cstring>
#include <cctype>
#include <cstdlib>
using namespace std;
const int MAXPERS = 100;
const int MAXTXT = 80;
const int DATELEN = 7;
class Person {
private:
int nr;
char* firstName;
char birthDate[DATELEN];
public:
Person() {
char fname[MAXTXT];
cout << "First name: "; cin.getline(fname, MAXTXT);
firstName = new char[strlen(fname) + 1];
strcpy(firstName, fname);
cout << "Birth date (DDMMYY): ";
cin >> birthDate; cin.ignore();
}
Person(int n, ifstream & in) {
nr = n;
char fname[MAXTXT];
cin.getline(fname, MAXTXT);
firstName = new char[strlen(fname) + 1];
strcpy(firstName, fname);
in >> birthDate;
}
void display() {
cout << "\nFirst name: " << firstName;
cout << "\nBorn: " << birthDate;
}
void writeToFile(ofstream & ut) {
ut << firstName << "\n" << birthDate;
}
};
void readFromFile();
Person* persons[MAXPERS + 1];
int lastUsed = 0;
int main() {
readFromFile();
persons[1]->display();
return 0;
}
void readFromFile() {
ifstream infile("ANSATTE.DAT");
if(infile) {
while(!infile.eof() && lastUsed < MAXPERS) {
int nr;
infile >> nr;
persons[++lastUsed] = new Person(nr, infile);
}
}
}
My file looks like this:
1
Andy
180885
2
Michael
230399
In your constructor you have
cin.getline(fnavn, MAXTXT);
So your program is waiting for you to type something in. If you meant to get the name from the file then you need
in.getline(fnavn, MAXTXT);
^^ ifstream object
You are also going to run into the issue of mixing >> with getline. You will need to add
infile.ignore(std::numeric_limits<std::streamsize>::max(), '\n')
after infile >> nr; in your while loop.
strlen(fname + 1) will be strlen(fname) - 1 if fname is one-character long or more and indeterminate if fname is zero-character long. It should be strlen(fname) + 1.
strlen(fnavn + 1) has the same issue and should be strlen(fnavn) + 1.
I am new to programming and I am having trouble reading data from a file and entering it into a struct array, while keeping track of each data being entered:
The file would contain:
Name, ID Number, and GPA
Courtney Love 1234569 3.5
Bob Joe 1234570 3.0
Dave Henry 1234571 2.9
struct Student
{
string name;
int id;
float GPA;
void printStudent();
};
Declare an array of Student type that can hold up to 5 members:
Student a_members[5];
Open the file, read in each line and store the data in the array, keep track of each student read in:
fstream file_;
file_.open ("students.txt");
if(file_.is_open())
{
while(file_.good())
{
}
}
else
{
cout << "File is not open"<< endl;
}
return 0;
I am stuck on the "while" conditional statement. After that I don't know what I should do to input the data from the file line by line and place into the "struct array". As of right now, I feel like I have tried everything! I deleted everything and figured it was best to start over. It was becoming too complicated! Maybe I am just not understanding the concept. If anyone can point me in the right direction, please do so! Thank you!
You should not use good(), just like you should not use eof().
(Neither is used in any decent beginner-level material, yet every beginner manages to find them. And then they wonder why it didn't work.)
You should instead rely on the fact that a stream itself is "true-ish" if it's in a good state, and just keep reading until it isn't.
Idiomatic C++ would look like this:
std::ifstream file("students.txt");
Student s;
while (file >> s.name >> s.id >> s.GPA)
{
// Process the student
}
or, a fancy version:
std::istream& operator>> (std::istream& is, Student& s)
{
return is >> s.name >> s.id >> s.GPA;
}
std::ifstream file("students.txt");
Student s;
while (file >> s)
{
// Process the student
}
(In your code, you'll need to also keep track of how many Students you've read.)
Here is one from possible solutions:
#include <iostream>
#include <vector>
#include <fstream>
struct Student
{
Student() : first_name(), surname(){}
char first_name[64];
char surname[64];
int id;
float GPA;
void printStudent()
{
std::cout << "Name: " << first_name << " " << surname << " ID: " << id << " GPA: " << this->GPA << std::endl;
}
};
std::vector<Student>student;
bool LoadFile(const char* filename)
{
if (filename == NULL)return false;
std::fstream stream(filename, std::ios::in);
if (!stream.is_open())return false;
else
{
char buffer[255]; // for solution 1!
while (!stream.eof())
{
memset(buffer, 0, sizeof(buffer));
Student _student;
#pragma region SOLUTION_1
//stream.getline(buffer, sizeof(buffer));
//sscanf(buffer, "%s %s %d %f", _student.first_name, _student.surname, &_student.id, &_student.GPA);
#pragma endregion
#pragma region SOLUTION_2
stream >> _student.first_name >> _student.surname >> _student.id >>_student.GPA;
#pragma endregion
student.push_back(_student);
student[student.size() - 1].printStudent();
}
}
return true;
}
int main()
{
LoadFile("students.txt");
getchar();
return 0;
}
i am having difficulty understanding how to pass a file into a function.
i have a file with 20 names and 20 test scores that needs to be read by a function. the function will then assign the names and scores to a structure called student.
my question is how would i write a function call with the appropriate parameters. ? to make my function read the data in the file. thanks.
CODE
// ask user for student file
cout << "Enter the name of the file for the student data to be read for input" << endl;
cout << " (Note: The file and path cannot contain spaces)" << endl;
cout << endl;
cin >> inFileName;
inFile.open(inFileName);
cout << endl;
// FUNCTION CALL how do i set this up properly?
ReadStudentData(inFile, student, numStudents );
void ReadStudentData(ifstream& infile, StudentType student[], int& numStudents)
{
int index = 0;
string lastName, firstName;
int testScore;
while ((index < numStudents) &&
(infile >> lastName >> firstName >> testScore))
{
if (testScore >= 0 && testScore <= 100)
{
student[index].studentName = lastName + ", " + firstName;
student[index].testScore = testScore;
index++;
}
}
numStudents = index;
}
The way you pass an ifstream into the function is perfectly fine.
I suspect that the problem lies in the way you are managing your array of StudentType and its size (numStudents). I would recommend changing your code to use an std::vector instead of a raw array. In general, you should always prefer vectors over arrays unless you have a really good reason to use an array.
vectors can grow to accommodate more data and keep track of their size, so you don't have to.
Also, it's a good idea for functions to return objects rather than modify objects passed through the parameter list.
#include <vector>
using namespace std;
vector<StudentType> ReadStudentData(ifstream& infile) {
vector<StudentType> students;
string lastName, firstName;
int testScore;
while (infile >> lastName >> firstName >> testScore) {
if (testScore >= 0 && testScore <= 100) {
StudentType student;
student.studentName = lastName + ", " + firstName;
student.testScore = testScore;
students.push_back(student);
}
}
return students;
}
// call the function
vector<StudentType> students = ReadStudentData(infile);
// or if you have a C++11 compiler
auto students = ReadStudentData(infile);
// use students.size() to determine how many students were read
The reference to the file object seems to be fine, but the array of StudentType objects maybe wrong.
Try this:
void ReadStudentData(ifstream& infile,
std::vector<StudentType>& vecStudents,
int& numStudents)