have a project where I'm supposed to ask the user to input a file name and then take that file and make an array of structs. I'm completely lost! Here is what i have so far
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
using namespace std;
string filename;
ifstream inFile;
struct ftballPlayer
{
int NO;
string first;
string last;
char POS;
char clas;
int height;
char ds;
int iheight;
string hometown;
};
int counter=0;
const int MAX_PLAYER=50;
void printList(const ftballPlayer list[], int listSize);
void printOne ( ftballPlayer two);
void getData(ifstream& inFile, ftballPlayer list[], int& listSize);
int main ()
{
ftballPlayer list[MAX_PLAYER] ;
cout << "Enter the name of the input file: " ;
cin >> filename;
inFile.open(filename.c_str () );
if (!inFile)
{
cout<<"Cannot Open Input File."<<endl;
cout<< "Program Terminates!"<<endl;
return 1;
}
inFile.ignore (200,'\n');
getData (inFile, list, counter);
for ( counter = 0;counter < 50;counter++)
{
printOne (list[ counter] ) ;
cout <<endl;
}
return 0;
}
void getData(ifstream& inFile, ftballPlayer list[], int& listSize)
{
ftballPlayer item ;
listSize = 0;
inFile >> item.NO >> item.first >> item.last
>> item.POS >> item.clas >> item.height
>> item.ds >> item.iheight >> item.hometown;
while (inFile )
{
list [listSize ] = item ;
listSize++;
inFile >> item.NO >> item.first >> item.last
>> item.POS >> item.clas >> item.height
>> item.ds >> item.iheight >> item.hometown;
}
inFile.close () ;
}
void printList(const ftballPlayer list[], int listSize)
{
int looper;
for ( looper = 0; looper < listSize ; looper++)
{
printOne ( list [looper] );
cout << endl ;
}
}
void printOne ( ftballPlayer one)
{
cout << fixed << showpoint << setprecision (2);
cout << "NO " << one.NO;
cout << setw(5) << left << " Name: " << one.first << " " << one.last;
cout << " POS " << one.POS << setw(5);
cout << "Class "<<one.clas<<setw (5);
cout << "Height "<<one.height<<" "<<one.ds<<" "<<one.iheight<<setw(5);
cout << "Hometown " << one.hometown << endl;
}
Can someone tell me if I'm on the right track? The print out I get is not even close to the text file which is this.
NO NAME POS CLASS HEIGHT WEIGHT Hometown/High School/Last College
60 Josh Mann OL SO 6-4 300 Virginia Beach, Va./Ocean Lakes
64 Ricky Segers K/P FR 5-11 185 Glen Allen, Va./Henrico
70 Brandon Carr OL RS_SR 6-2 305 Chesapeake, Va./Western Branch/Fork Union Military Academy
53 Calvert Cook LB FR 6-0 250 Norfolk, Va./Booker T. Washington
51 Michael Colbert DE RS_SR 6-1 230 Fayetteville, N.C./E.E. Smith
22 T.J. Cowart CB RS_JR 5-9 190 Virginia Beach, Va./Ocean Lakes
1 Jakwail Bailey WR SO 5-11 185 Haddonfield, N.J./Paul VI
25 Andre Simmons S JR 6-0 205 Lorton, Va./South County/Vanderbilt
34 Johnel Anderson RB FR 5-8 180 Sicklerville, N.J./Paul VI
This is one of three that the user can input but they all have the same type of information. I've looked in my text book and have been hunting online for hours and I can't find anything about doing this when the user inputs the file instead of just starting with a file. Any help or direction would be greatly appreciated.
A few things that I see wrong right away.
struct ftballPlayer
{
int NO;
string first;
string last;
char POS; // Should be multiple characters
char clas; // Should be multiple characters
int height;
char ds;
int iheight;
string hometown;
};
I suspect that if you get the right sizes of your POS/ clas, it will work better. Why not make them strings?
Also, there is some issue with reading the last bit. It looks like you have to look for the / to tell the various pieces apart, and I don't see you doing that.
Overall, it would be much cleaner to read this if you could change the format of the input, but I suspect you aren't able to. Comma separated values are very easy to read, as are any other divider.
Related
Basically my program is giving me a load of errors with my filereading program when trying to compile. The goal is to get the user to enter the threshold number and the strings that are equal to or greater than that threshold number will be outputted. The program fails at that because there are several errors with the code. How to fix the errors within the code?
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
int read_airports(string cities[], int threshold);
int main()
{
ifstream fin;
fin.open("airports.txt");
if (fin.is_open())
{
string cities[20];
int count, threshold;
count = read_airports(cities, threshold);
while(!fin.eof())
{
fin >> threshold;
cout << "Enter a threshold number" << endl;
cin >> threshold;
if (fin.good())
{
if (cities >= threshold)
{
cout << cities << endl;
}
}
}
fin.close();
}
return 0;
}
int read_airports(string cities[], int threshold)
{
}
Here is the text file where this code is based off of.
LAX Los-Angeles 40
JFK New-York 39
IAH Houston 26
LCY London 34
PAR Paris 15
TYO Tokyo 11
SEL Seoul 5
YYZ Toronto 28
[Warning: none of this code has been tested at all.]
I would structure the code rather differently.
I would create a structure for the data about each airport/city:
struct airport {
std::string abbreviation;
std::string city_name;
int threshold;
};
Then I'd overload operator>> to read one of those records from a stream, and operator<< to write one to a stream:
std::istream &operator>>(std::istream &is, airport &ap) {
return is >> ap.abbreviation >> ap.city_name >> ap.threshold;
}
std::ostream &operator<<(std::ostream &os, airport const &ap) {
return os << ap.abbreviation << "\t" << ap.city_name << "\t" << ap.threshold;
}
Then I'd write code to desired data from a file of those to standard output:
std::ifstream infile("airportdata.txt");
std::cout << "Please enter minimum threshold value: ";
int threshold;
std::cin >> threshold;
std::copy_if(std::istream_iterator<airport>(infile), {},
std::ostream_iterator<airport>(std::cout, "\n"),
[=](airport const &ap) { return ap.threshold > threshold; });
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.
I am a beginner programer trying to learn C++. I am trying to read the following information from a file:
Dean DeFino 88 98 99
Sally Johnson 78 89 82
Bill Benny 75 79 81
Thomas Billows 78 84 89
However, I get the following output and I can't figure out why:
Dean DeFino 88 98 99
0 0 0
Sally Johnson 78 89 82
0 0 0
Here is the code:
#include <fstream>
#include <iostream>
#include <iomanip>
using namespace std;
const int NAMESIZE = 15;
const int MAXRECORDS = 50;
struct Grades // declares a structure
{
char name[NAMESIZE + 1];
int test1;
int test2;
int final;
};
typedef Grades gradeType[MAXRECORDS];
// This makes gradeType a data type
// that holds MAXRECORDS
// Grades structures.
void readIt(ifstream&, gradeType, const int);
int main()
{
ifstream indata;
indata.open("graderoll.dat");
int numRecord = 4;
gradeType studentRecord;
if(!indata)
{
cout << "Error opening file. \n";
cout << "It may not exist where indicated" << endl;
return 1;
}
readIt(indata, studentRecord, MAXRECORDS);
// output the information
for (int count = 0; count < numRecord; count++)
{
cout << studentRecord[count].name << setw(10)
<< studentRecord[count].test1
<< setw(10) << studentRecord[count].test2;
cout << setw(10) << studentRecord[count].final << endl;
}
return 0;
}
void readIt(ifstream& inData, gradeType gradeRec, const int max)
{
int total = 0;
inData.get(gradeRec[total].name, NAMESIZE);
while (inData)
{
inData >> gradeRec[total].test1;
inData >> gradeRec[total].test2;
inData >> gradeRec[total].final;
total++;
inData.clear();
inData.get(gradeRec[total].name, NAMESIZE);
}
}
Any suggestions to help me out with this?
I SOLVED THE ISSUE:
void readIt(ifstream& inData, gradeType gradeRec, const int max)
{
int total = 0;
inData.get(gradeRec[total].name, NAMESIZE);
while (inData)
{
inData >> gradeRec[total].test1;
inData >> gradeRec[total].test2;
inData >> gradeRec[total].final;
total++;
inData.ignore(NAMESIZE, '\n');
inData.get(gradeRec[total].name, NAMESIZE);
}
}
inData.ignore(NAMESIZE, '\n'); will make the character array work properly. This is because the character array is limited to 15 characters. So if specify to ignore the next 15 characters and or until a newline escape sequence is encountered, each line of the file is read properly.
The problem is your use of:
while (inData)
When converting an iostream to a boolean, the boolean reflects the state of the EOF flag. However, the EOF flag is not set until after you try to read data from the end of the file.
So what happens is your code successfully reads the last line of your file, then loops around and the EOF flag is not set yet, and tries to read one more line from the file. This doesn't read any actual data and you get zeros. After that, the EOF flag is set and your loop terminates.
One way to fix this might be to test the EOF flag after reading the expected data, so:
while (true)
{
inData >> gradeRec[total].test1;
inData >> gradeRec[total].test2;
inData >> gradeRec[total].final;
if (!inData) {
break;
}
total++;
inData.clear();
inData.get(gradeRec[total].name, NAMESIZE);
}
You could also rearrange your loop a bit so you don't have code to read the name twice, once outside the loop and once at the end.
I tried earlier to use a for loop to put data in but became too problematic. So I tried to use a while loop, it works but when I tried to debug it it continued to put -858993460 into every slot. The .dat file is in the right spot and opens.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
struct record
{
int item_id;
string item_type;
float item_price;
int num_stock;
string item_title;
string item_author;
int year_published;
};
void read_all_records(record records[], int &valid_entries);
int num_inventory_of_type(record records[], string type, int &valid_entries);
const int max_array = 100;
int main()
{
int valid_entries = 0;
record records[max_array];
read_all_records(records, valid_entries);
cout << "Stock Report" << endl;
cout << "------------" << endl;
int book = num_inventory_of_type(records, "book", valid_entries);
cout << "Book's In Stock: " << book << endl;
int cd = num_inventory_of_type(records, "cd", valid_entries);
cout << "CD's In Stock: " << cd << endl;
int dvd = num_inventory_of_type(records, "dvd", valid_entries);
cout << "DVD's In Stock: " << dvd << endl;
return 0;
}
void read_all_records(record records[], int &valid_entries)
{
ifstream invfile;
invfile.open("inventory.dat");
if (!invfile.is_open())
{
cout<<"file open failed";
exit(1);
}
while(invfile.good() && valid_entries < max_array)
{
invfile >> records[valid_entries].item_id >> records[valid_entries].item_type
>> records[valid_entries].item_price >> records[valid_entries].num_stock
>> records[valid_entries].item_title >> records[valid_entries].item_author
>> records[valid_entries].year_published;
if(!invfile.good())
break;
valid_entries++;
}
invfile.close();
}
int num_inventory_of_type(record records[], string type, int &valid_entries)
{
int count = 0;
int holder = 0;
for (int count = 0; count<valid_entries; count++);
{
if (records[count].item_type == type)
{
holder+=records[count].num_stock;
}
}
return holder;
}
the .dat file is
123456
book
69.99
16
Problem_Solving_With_C++
Walter_Savitch
2011
123457
cd
9.99
32
Sigh_No_More
Mumford_and_Sons
2010
123458
dvd
17.99
15
Red_State
Kevin_Smith
2011
123459
cd
9.99
16
The_Church_Of_Rock_And_Roll
Foxy_Shazam
2012
123460
dvd
59.99
10
The_Walking_Dead_Season_1
Robert_Kirkman
2011
all are on new lines, no spaces.
Basically it should start, run the read_all_records function and put the .dat data into the array. However, I put the cout << records[count].item_id; in the while loop just to see if the data was actually going in, and I get -858993460 each time. After that it should run the next function 3 times and return how many of each books there are.
You used the integer type int on item_price. invfile >> records[count].item_price will then only extract 69 instead of 69.99, thus resulting in a error when you try to extract the year_published.
Use a float or double instead.
struct record
{
int item_id;
string item_type;
float item_price;
int num_stock;
string item_title;
string item_author;
int year_published;
};
/* skipped identical lines */
while(invfile.good() && count < max_array)
{
invfile >> records[count].item_id >> records[count].item_type
>> records[count].item_price >> records[count].num_stock
>> records[count].item_title >> records[count].item_author
>> records[count].year_published;
cout << records[count].item_price << endl;
if(!invfile.good())
break;
cout << records[count].item_id << endl;
count++;
}
invfile.close();
Note that you have an extra semicolon in for (int count = 0; count<max_array; count++);. I guess you didn't intend this, so remove it.
This isn't a direct answer to the problem, but perhaps it will go away after a refactoring:
std::istream& operator>>(std::istream& is, record& r) {
return is >> r.item_id >> r.item_type >> … >> r.year_published;
}
int main () {
if (std::ifstream invfile("inventory.dat")) {
std::vector<record> records((std::istream_iterator<record>(invfile)),
std::istream_iterator<record>());
num_inventory_of_type(records, "dvd");
num_inventory_of_type(records, "cd");
num_inventory_of_type(records, "book");
}
}
If you still want to print out each record as you read it, the code can be rearranged as follows:
std::vector<record> records;
for (std::istream_iterator<record> i(invfile);
i != std::istream_iterator<record>(); ++i)
{
records.push_back(*i);
std::cout << i->item_id << "\n";
}
You need to change int item_price; to a float so -> float item_price;
and as mentioned above you need to swap the count++; and cout << records[count].item_id line.
After these two changes it will work properly.
struct record
{
int item_id;
string item_type;
float item_price; // <--- Needs to be a float
int num_stock;
string item_title;
string item_author;
int year_published;
};
// This order is required because you are storing in the current 'count' record and then you need to print it. Then increment the count to store the next record
cout << records[count].item_id;
count++;