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 :-)
Related
So basically all this program does is read in the data into the array of structs of student_type and all the print_students functions does is output the data i get mostly the correct output but i also get random huge numbers.The file data contains the following info and my code is below how do i fix my output?
Smith
John
123456
3.4
J
1750.4
302
Fairmont St NW
Washington
DC
20059
Smitty
Frank
78910
2.7
F
1940.7
302
Sixth St SW
Washington
DC
20059
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
struct Address_type
{
int street_no;
string street_name;
string city;
string state;
int zip;
};
struct student_type
{
string lname;
string fname;
int ID;
float GPA;
char classification;
float account_balance;
Address_type student_address;
};
void print_students(student_type[]); // prototypein
int main()
{
ifstream myfile;
student_type students[5];
myfile.open("infile.txt");
string name1, name2, name3;
for (int i = 0; i < 2; i++) {
myfile >> students[i].lname;
myfile >> students[i].fname;
myfile >> students[i].ID;
myfile >> students[i].GPA;
myfile >> students[i].classification;
myfile >> students[i].account_balance;
myfile >> students[i].student_address.street_no;
myfile >> name1 >> name2 >> name3;
students[i].student_address.street_name = name1 + " " + name2 + " " + name3;
myfile >> students[i].student_address.city;
myfile >> students[i].student_address.state;
myfile >> students[i].student_address.zip;
print_students(students);
}
myfile.close();
}
void print_students(student_type students[])
{
for (int i = 0; i < 2; i++) {
cout << students[i].lname << endl;;
cout<< students[i].fname<<endl;
cout<< students[i].ID<<endl;
cout<< students[i].GPA<<endl;
cout<< students[i].classification<<endl;
cout<< students[i].account_balance<<endl;
cout<< students[i].student_address.street_no<<endl;
cout<<students[i].student_address.street_name<<endl;
cout << students[i].student_address.city << endl;
cout << students[i].student_address.state << endl;
cout << students[i].student_address.zip << endl;
}
}
It looks like you're printing all of your student data on the first iteration of the loop. You should hold off until you've loaded all your data.
Additionally, in C++ it's important to use the Standard Library containers and do your best to avoid C-style fixed-length arrays in situations like this where you're reading in from a file of unknown length.
That is use this:
std::vector<student_type> students;
This can be added to with things like push_back on a properly composed student_type record.
Then you can pass that through by reference to any function that needs it, like print_students for example. Right now, for whatever reason, you just assume that there will be three entries in that array (of length five?) and go ahead and dump it out even if it wasn't populated.
I'm trying to look for what is wrong in this fragment of code. It says the error : [Error] no match for 'operator>>' in 'inputData >> Player[i].AthleteType::firstName' for the line:
inputData >> Player[i].firstName;
Can someone tell me what this means? And also if this is the right way to read data from a file that looks like this:
Peter Gab 2653 Kenya 127
Usian Bolt 6534 Jamaica 128
Other Name 2973 Bangladesh -1
Bla Bla 5182 India 129
Some Name 7612 London -1
//this is the structure
struct AthleteType
{
string firstName[SIZE];
string lastName[SIZE];
int athleteNumber[SIZE];
string country[SIZE];
int athleteTime[SIZE];
};
void readInput(int SIZE)
{
AthleteType Player[SIZE];
ifstream inputData("Athlete info.txt");
int noOfRecords=0;
for (int i=0; i < SIZE; i++, noOfRecords++)
{
inputData >> Player[i].firstName;
inputData >> Player[i].lastName;
inputData >> Player[i].athleteNumber;
inputData >> Player[i].country;
inputData >> Player[i].athleteTime;
}
for (int i=0; i < noOfRecords; i++)
{
cout << "First Name: " << Player[i].firstName << endl;
cout << "Last Name: " << Player[i].lastName << endl;
cout << "Athlete Number: " << Player[i].athleteNumber << endl;
cout << "Country: " << Player[i].country << endl;
cout << "Athlete Time: " << Player[i].athleteTime << endl;
cout << endl;
}
}
There are several problems with your attempt. Firstly your struct
struct AthleteType {
string firstName[SIZE];
string lastName[SIZE];
int athleteNumber[SIZE];
string country[SIZE];
int athleteTime[SIZE];
};
Your compiler error is telling you that you can't read into an array of strings, inputData >> firstName[SIZE];. One string at a time is fine of course.
If i peer into my crystal ball, I see that you want to store several athletes. This should be done using a vector.
vector<Athlete> athletes;
And the struct can then be
struct Athlete
{
string firstName;
string lastName;
int athleteNumber;
string country;
int athleteTime;
};
One athlete per object.
When reading from an input file you want to read based on read success.
while(inputData >> athlete){
athletes.push_back(athlete);
}
You can do this by overloading operator>> (istream&, Athlete& ); or you can write a function that does a similar job.
istream& readAthlete(istream& in, Athlete& at){
return in >> at.firstName >> at.lastName >> at.athleteNumber >> ... and so on;
}
Now the read function can be written as
vector<Athlete> readInput(string filename){
vector<Athlete> athletes;
ifstream inputData(filename);
Athlete athlete;
while(readAthlete(inputData, athlete)){
athletes.push_back(athlete);
}
return athletes;
}
This is not tested code, it might work, it might not work, but it should give you a reasonable path forward.
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.
I have this program that changes negative numbers to positive in my file.
It works, but negative numbers in the file don't change.
for example, if I have this numbers in my file : 12 2 -3 -1
when I run the program, the sum of numbers will be 18, but when I open my file again, I see
12 2 -3 -1 . What should I do to see 12 2 3 1 ?
here is my code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
string name;
cin >> name;
int number;
int num=0;
ifstream myFile(name, ios::in);
ofstream mine(name, ios::app);
while(myFile >> number)
{
num += (number<0 ? -number : number);
mine << num;
}
cout << "num = " << num << endl;
system("pause");
return 0;
}
Opening the file for reading and writing for the same time is generally not a bad idea. You probably got an I/O error during opening mine, but since you didn't check it, the program ignored your writes silently. Try reading the file contents first (to a vector for example), then close the file for reading and open again for writing (not appending, because that would leave the old contents in the file).
When writing the values back to the file, also write whitespace after the number, otherwise you'll just get a string of digits in the file but you won't know where one begins and another ends.
Your program now doesn't "change negative numbers to positive" but it prints the cumulative sum of absolute values to the file.
Try writing to the standard output first so you won't ruin your file while you are testing. If it works, then change cout to your output stream.
Here is the code.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cstdlib>
using namespace std;
int main()
{
string name;
cin >> name;
int number;
int num=0;
ifstream myFile(name, ios::in);
vector<int> vec;
while(myFile >> number)
{
vec.push_back(abs(number));
}
ofstream mine(name, ios::out);
for (vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
num += *it;
mine << *it << " ";
}
cout << "num = " << num << endl;
return 0;
}
Opening a read and write file streams for the same file and process at the same time is inviting file corruption. Use ostringstream to store the values read from the file. The values
from the file are read, and the values stored in the ostringstream
buffer. The ifstream object is closed before re-opening the file with
an ofstream object so that the buffer contents can be saved.
Note the ios::app flag has been removed. Otherwise the new values
will append to the existing values.
abs() function is used to write back the absolute values - this
forces all values positive.
#include<sstream>
int main()
{
string name;
cin >> name;
int number;
int num=0;
ifstream myfile(name.c_str(), ios::in);
ostringstream oss;
while (myfile >> number)
{
num += (number<0 ? -number : number);
oss << abs(number) << " ";
}
myfile.close();
ofstream mine(name.c_str());
cout << "num = " << num << endl;
mine << oss.str();
return 0;
}
string name;
cin >> name;
int number=0;
int sum=0;
string outname=name+".pos.txt";
ifstream myFile(name,ifstream::in);
ofstream mine(outname, ofstream::out );
while(myFile >> number)
{
number= (number<0 ? -number : number);
sum+=number;
mine << number<<' ';
}
myFile.close();
mine.close();
cout << "sum = " << sum << endl;
system("pause");
I have the following structure:
struct productInfo
{
int item;
string details;
double cost;
};
I have a file that will input 10 different products that each contain an item, details, and cost. I have tried to input it using inFile.getline but it just doesn't work. Can anyone give me an example of how to do this? I would appreciate it.
Edit
The file contains 10 lines that look like this:
570314,SanDisk Sansa Clip 8 GB MP3 Player Black,55.99
Can you provide an example please.
Edit
Sorry guys, I am new to C++ and I don't really understand the suggestions. This is what I have tried.
void readFile(ifstream & inFile, productInfo products[])
{
inFile.ignore(LINE_LEN,'\n'); // The first line is not needed
for (int index = 0; index < 10; index++)
{
inFile.getline(products[index].item,SIZE,DELIMETER);
inFile.getline(products[index].details,SIZE,DELIMETER);
inFile.getline(products[index].cost,SIZE,DELIMETER);
}
}
This is another approach that uses fstream to read the file and getline() to read each line on the file. The parsing of the line itself was left out on purpose since other posts have already done that.
After each line is read and parsed into a productInfo, the application stores it on a vector, so all products could be accessed in memory.
#include <iostream>
#include <fstream>
#include <vector>
#include <iterator>
#include <string>
using namespace std;
struct productInfo
{
int item;
string details;
double cost;
};
int main()
{
vector<productInfo> product_list;
ifstream InFile("list.txt");
if (!InFile)
{
cerr << "CouldnĀ“t open input file" << endl;
return -1;
}
string line;
while (getline(InFile, line))
{ // from here on, check the post: How to parse complex string with C++ ?
// https://stackoverflow.com/questions/2073054/how-to-parse-complex-string-with-c
// to know how to break the string using comma ',' as a token
cout << line << endl;
// productInfo new_product;
// new_product.item =
// new_product.details =
// new_product.cost =
// product_list.push_back(new_product);
}
// Loop the list printing each item
// for (int i = 0; i < product_list.size(); i++)
// cout << "Item #" << i << " number:" << product_list[i].item <<
// " details:" << product_list[i].details <<
// " cost:" << product_list[i].cost << endl;
}
EDIT: I decided to take a shot at parsing the line and wrote the code below. Some C++ folks might not like the strtok() method of handling things but there it is.
string line;
while (getline(InFile, line))
{
if (line.empty())
break;
//cout << "***** Parsing: " << line << " *****" << endl;
productInfo new_product;
// My favorite parsing method: strtok()
char *tmp = strtok(const_cast<char*>(line.c_str()), ",");
stringstream ss_item(tmp);
ss_item >> new_product.item;
//cout << "item: " << tmp << endl;
//cout << "item: " << new_product.item << endl;
tmp = strtok(NULL, ",");
new_product.details += tmp;
//cout << "details: " << tmp << endl;
//cout << "details: " << new_product.details << endl;
tmp = strtok(NULL, " ");
stringstream ss_cost(tmp);
ss_cost >> new_product.cost;
//cout << "cost: " << tmp << endl;
//cout << "cost: " << new_product.cost << endl;
product_list.push_back(new_product);
}
It depends on what's in the file? If it's text, you can use the redirect operator on a file input stream:
int i;
infile >> i;
If it's binary, you can just read it in to &your_struct.
You have to
0) Create a new instance of productInfo, pinfo;
1) read text (using getline) to the first comma (','), convert this string to an int, and put it into pinfo.item.
2) read text to the next comma and put it into pinfo.details;
3) read text to the endline, convert the string to a double, and put it into pinfo.cost.
Then just keep doing this until you reach the end of the file.
Here is how I would use getline. Note that I use it once to read from the input file, and then again to chop that line at ",".
ostream& operator>>(istream& is, productInfo& pi)
{
string line;
getline(is, line); // fetch one line of input
stringstream sline(line);
string item;
getline(sline, item, ',');
stringstream(item) >> pi.item; // convert string to int
getline(sline, item, ',');
pi.details = item; // string: no conversion necessary
getline(sline, item);
stringstream(item) >> pi.cost; // convert string to double
return is;
}
// usage:
// productInfo pi; ifstream inFile ("inputfile.txt"); inFile >> pi;
N.b.: This program is buggy if the input is
99999,"The Best Knife, Ever!",16.95