Reputation: 45
Firstly, I'm using DEVC++, my goal of this code is to be able to read a text file into an array of structs. My text file is written like this: animalName:animalType:RegistrationNo:ProblemNo.
My issue with the below code is that it only seems to be running the while loop once.
I have looked up similar code but it uses to_string() and stoi but I don't think DEVC++ runs C++11 so I was wondering if there's an easy fix to my existing code or if there's another way to accomplish reading a text file which is made up of strings and ints
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#define MAX 100
using namespace std;
struct Animal
{
string animalName;
string animalType;
int Registration;
int Problem;
};
int main()
{
Animal ani[MAX];
ifstream infile;
int i = 0;
infile.open("Animals.txt");
if (!infile) {
cout << "Unable to open file";
exit(1);
}
int count = 0;
while (infile.good()) {
getline(infile, ani[i].animalName, ':');
getline(infile, ani[i].animalType, ':');
infile >> ani[i].Registration, ':';
infile >> ani[i].Problem, '.';
count++;
i++;
}
infile.close();
for (int i = 0; i < count; i++) {
cout << ani[i].animalName << " ";
}
for (int i = 0; i < count; i++) {
cout << ani[i].animalType << " ";
}
for (int i = 0; i < count; i++) {
cout << ani[i].Registration << " ";
}
for (int i = 0; i < count; i++) {
cout << ani[i].Problem<< " ";
}
return 0;
}
Upvotes: 2
Views: 325
Reputation: 33931
You are misusing the comma operator.
infile >> ani[i].Registration, ':';`
doesn't read and discard the ':'
, leading to bloody death... Sorry. Leading to a parsing error when
infile >> ani[i].Problem
tries to turn the ':'
into an integer. This places infile
into the fail state,
while (infile.good())
finds that infile
isn't good, and exits the loop.
You will have to do something along the line of
std::string temp;
std::getline(infile, temp, ':');
ani[i].Registration = std::stoi(temp);
to read the stream up to the ':'
delimiter into a std::string
and then turn the string
into an integer with std::stoi
.
That's the bulk of the bug. But...
while (infile.good())
tests that the stream is good BEFORE reading from it. This allows the stream to fail utterly while reading without any tests before the failed results are used.
while (getline(infile, ani[i].animalName, ':') &&
getline(infile, ani[i].animalType, ':') &&
getline(infile, temp1, ':') &&
getline(infile, temp2, '.'))
{ // only goes into loop if everything was read
// may also have to eliminate a newline here
ani[i].Registration = std::stoi(temp1);
ani[i].Problem = std::stoi(temp2); //exception if bad
i++;
}
An even better approach is to make a >>
operator overload for Animal
because that lets you write a main loop that looks like
while (infile>> ani[i])
{
i++;
}
And that's so simple that all rejoice. See What are the basic rules and idioms for operator overloading? for information on writing the >>
operator and much more general wisdom.
Upvotes: 3