What does "no match for 'operator >>'" mean in my code? - c++

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.

Related

How to fix output?

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.

Code outputs nonsense to output file instead of string?

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 :-)

How to read spaced string with get line() from a file?

I want to read a name like "Penelope Pasaft" all together from a file and save it to a variable "person". I have understood that I have to use the get line(file, person). But I have a problem doing it because I want also to read other variables before.
Imagine a .txt like:
1
+546343864246
Penelope Pasaft
So here is the code:
typedef struct {
string number; //I use string because it is an alphanumeric cellphone number
string person;
int identifier;
} cellphone;
ifstream entry;
entry.open(fileName.c_str());
cellphone c[10];
int j=0;
if(entry)
{
cout << "The file has been successfully opened\n\n";
while(!entry.eof())
{
entry >> c[j].identifier >> c[j].number;
getline(entry,c[j].person);
cout << "Start: " << c[j].identifier << "\nNumber: " <<
c[j].number << "\nPerson: " << c[j].person << endl << endl;
j++;
}
}
Well the problem I have it's that it doesn't seem to print or save me any data to the variable c[j].person
Problem is that your input file has empty lines in it.
If you use cin >> only, it will work OK because >> operator skips blank chars (but stops at blank chars, as you noted: can't have it all)
On the other hand, getline will read the line, even if it's blank.
I propose the following standalone code slightly modified from yours: note the loop until end of file or non-blank line.
(note: it there are spaces only in the line, it will fail)
I also replaced array by a vector, resized on the fly (more C++-ish)
#include<iostream>
#include<fstream>
#include<string>
#include<vector>
using namespace std;
typedef struct {
string number; //I use string because it is an alphanumeric cellphone number
string person;
int identifier;
} cellphone;
int main()
{
ifstream entry;
string fileName = "file.txt";
entry.open(fileName.c_str());
vector<cellphone> c;
cellphone current;
int j=0;
if(entry)
{
cout << "The file has been successfully opened\n\n";
while(!entry.eof())
{
entry >> current.identifier >> current.number;
while(!entry.eof())
{
getline(entry,current.person);
if (current.person!="") break; // stops if non-blank line
}
c.push_back(current);
cout << "Start: " << c[j].identifier << "\nNumber: " << c[j].number << "\nPerson: " << c[j].person <<endl<<endl;
j++;
}
}
return 0;
}
output:
The file has been successfully opened
Start: 1
Number: +546343864246
Person: Penelope Pasaft

C++ Read characters, integers and doubles with dividing lines from text file into 2D array

Bulbasaur|Grass| |2|16|45|65|65|45|0.059
Ivysaur|Grass|Poison|3|32|60|80|80|60|0.059
Venusaur|Grass|Poison| | |80|100|100|80|0.059
Torchic|Fire| |23|16|45|70|50|45|0.045
Combusken|Fire|Fighting|24|36|60|85|60|55|0.045
Blaziken|Fire|Fighting| | |80|110|70|80|0.045
These are some data in my text file, which stores Pokemon's name, type 1, type 2, index number of evolved Pokemon from the list, and stats, with character "|" as dividing lines, how do I read all hundreds of similar data into a 2D array? Or any other form of array which gives better result?
These are my C++ codes, and the result are totally failure.
ifstream inFile;
inFile.open("PokemonBaseStats.txt");
if (inFile.fail())
{
cerr << "Could not find file" << endl;
}
vector<string> code;
string S;
while (inFile >> S) {
code.push_back(S);
inFile >> name >> type1 >> type2 >> evolveTo >> evolveLevel >> hp >> atk >> def >> spd >> catchRate;
cout << name << type1 << type2 << evolveTo << evolveLevel << hp << atk << def << spd << catchRate;
}
system("PAUSE");
return 0;
The output is:-
I wrote a piece of code to do that but I'm not sure if it is exactly what you wanted:
struct Pokemon
{
public:
std::string Name;
std::string Type1;
std::string Type2;
int IdxVector[6];
float Stat;
};
int main(int argc, char *argv[])
{
std::string TxtLine;
int count;
std::ifstream F("./TextFile.txt");
std::list<Pokemon> PList;
while(std::getline(F,TxtLine))
{
Pokemon P;
int idx=TxtLine.find_first_of('|');
std::string Element=TxtLine.substr(0,idx);
P.Name=Element;
TxtLine.erase(0,idx+1);
idx=TxtLine.find_first_of('|');
Element=TxtLine.substr(0,idx);
P.Type1=Element;
TxtLine.erase(0,idx+1);
idx=TxtLine.find_first_of('|');
Element=TxtLine.substr(0,idx);
P.Type2=Element;
TxtLine.erase(0,idx+1);
for(int i=0;i<6;i++)
{
idx=TxtLine.find_first_of('|');
Element=TxtLine.substr(0,idx);
P.IdxVector[i]=atoi(Element.c_str());
if(Element.compare(" ")==0)
P.IdxVector[i]=-1;
TxtLine.erase(0,idx+1);
}
P.Stat=atof(TxtLine.c_str());
PList.push_back(P);
}
return 0;
}

WHILE loop and data entry

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++;