I'm very new to C and am having difficulty with the getline() command skipping the lines from the input file and am unsure what my issue is. The goal of the program is to read in an input file one "section" at a time, put it into a structure, and then output that line to the file, and continue until there aren't any more lines in the file.
The input files look like this:
000.000.0000
lastname
street
city
state
zipcode
firstname
000.000.0000
lastname
street
....
etc... when I run the program, it outputs to the out file, but it skips and lines and continues to repeat those same lines until I forcibly stop the program.
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <climits>
using namespace std;
struct Person
{
string firstName;
string lastName;
string phoneNumber;
};
struct Address
{
string streetNum_Name;
string city;
string state;
int zip_code;
};
struct Info
{
Person person;
Address address;
};
void printFileHeader(ofstream& outFile);
bool openInputFile(ifstream& inFile);
void openOutputFile(ofstream& outFile);
struct Info readInfo(ifstream& inFile, Info&);
void printInfo(ofstream& outFile, Info&);
int main()
{
ifstream inFile;
ofstream outFile;
bool fileStreamState;
Info person;
printFileHeader(outFile);
fileStreamState = openInputFile(inFile);
openOutputFile(outFile);
cout << "Processing information. Please Wait...." << endl << endl;
while (fileStreamState) {
readInfo(inFile, person);
printInfo(outFile, person);
}
outFile << setw(7) << "-----" << setw(20) << "---------" << setw(15) << "----------" << setw(20) << "----"
<< setw(12) << "------------" << endl;
cout << "Program has finished execution." << endl;
inFile.close();
outFile.close();
}
void printFileHeader(ofstream& outFile) {
outFile << left << setw(7) << "Entry" << setw(20) << "Last Name" << setw(15) << "First Name" << setw(20) << "City"
<< setw(12) << "Phone Number" << endl;
outFile << setw(7) << "-----" << setw(20) << "---------" << setw(15) << "----------" << setw(20) << "----"
<< setw(12) << "------------" << endl;
}
bool openInputFile(ifstream& inFile) {
string filename;
cout << "Enter the name of the input file: ";
cin >> filename;
cout << filename << endl << endl;
inFile.open(filename.c_str());
while(inFile.fail()) {
cout << string(15,'*') << " File Open Error " << string(15,'*') << endl;
cout << "==> Input file failed to open properly!!\n";
cout << "==> Attempted to open file: " << filename << endl;
cout << "==> Try Again\n";
cout << string(47,'*') << endl<< endl;
inFile.clear();
cout << "Enter in the name of the input file: ";
cin >> filename;
cout << filename << endl << endl;
inFile.open(filename.c_str());
}
return 1;
}
void openOutputFile(ofstream& outFile) {
string filename;
cout << "Enter the name of the output file: ";
cin >> filename;
cout << filename << endl << endl;
outFile.open(filename.c_str());
while(outFile.fail()) {
cout << string(15,'*') << " File Open Error " << string(15,'*') << endl;
cout << "==> Output file failed to open properly!!\n";
cout << "==> Attempted to open file: " << filename << endl;
cout << "==> Try Again\n";
cout << string(47,'*') << endl<< endl;
outFile.clear();
cout << "Enter in the name of the input file: ";
cin >> filename;
cout << filename << endl << endl;
outFile.open(filename.c_str());
}
}
struct Info readInfo(ifstream& inFile, Info& record) {
getline(inFile, record.person.phoneNumber);
cout << record.person.phoneNumber << endl;
inFile.ignore(INT_MAX, '\n');
getline(inFile, record.person.lastName);
cout << record.person.lastName << endl;
inFile.ignore(INT_MAX, '\n');
getline(inFile, record.address.streetNum_Name);
cout << record.address.streetNum_Name << endl;
inFile.ignore(INT_MAX, '\n');
getline(inFile, record.address.city);
cout << record.address.city << endl;
inFile.ignore(INT_MAX, '\n');
getline(inFile, record.address.state);
cout << record.address.state << endl;
inFile.ignore(INT_MAX, '\n');
inFile >> record.address.zip_code;
cout << record.address.zip_code << endl;
inFile.ignore(INT_MAX, '\n');
getline(inFile, record.person.firstName);
cout << record.person.firstName << endl;
return record;
}
void printInfo(ofstream& outFile, Info& record) {
static int entry = 0;
entry ;
outFile << left << setw(7) << entry << setw(20) << record.person.lastName << setw(15) << record.person.firstName
<< setw(20) << record.address.city << setw(12) << record.person.phoneNumber << endl;
}
Any help would be much appreciated, thanks!
CodePudding user response:
You are ignore()
'ing data in readInfo()
that you should not be ignoring. getline()
reads everything up to and including a line break, and then discards the line break. So you are reading the phoneNum
data, then ignore()
'ing the lastName
data, then reading the streetNum
data, then ignore()
'ing the city
data, etc. You need to remove all of the ignore()
's after getline()
's, the only ignore()
you need is the one after reading the zip_code
with operator>>
:
struct Info readInfo(ifstream& inFile, Info& record) {
getline(inFile, record.person.phoneNumber);
cout << record.person.phoneNumber << endl;
getline(inFile, record.person.lastName);
cout << record.person.lastName << endl;
getline(inFile, record.address.streetNum_Name);
cout << record.address.streetNum_Name << endl;
getline(inFile, record.address.city);
cout << record.address.city << endl;
getline(inFile, record.address.state);
cout << record.address.state << endl;
inFile >> record.address.zip_code;
inFile.ignore(INT_MAX, '\n');
cout << record.address.zip_code << endl;
getline(inFile, record.person.firstName);
cout << record.person.firstName << endl;
return record;
}
That being said, your while
loop in main()
is broken. Once readInfo()
reads the last record in the file, if the last firstName
ends with a line break then EOF hasn't been reached yet, so while (fileStreamState)
will still evaluate as true and the loop will call readInfo()
and printInfo()
again, even though there is no more record data left to read/print.
There is no good reason to have readInfo()
take the struct
as a reference and also return it. So you should return a bool
instead indicating success/fail:
bool readInfo(ifstream& inFile, Info&);
...
while (readInfo(inFile, person)) {
printInfo(outFile, person);
}
...
bool readInfo(ifstream& inFile, Info& record) {
getline(inFile, record.person.phoneNumber);
cout << record.person.phoneNumber << endl;
getline(inFile, record.person.lastName);
cout << record.person.lastName << endl;
getline(inFile, record.address.streetNum_Name);
cout << record.address.streetNum_Name << endl;
getline(inFile, record.address.city);
cout << record.address.city << endl;
getline(inFile, record.address.state);
cout << record.address.state << endl;
inFile >> record.address.zip_code;
inFile.ignore(INT_MAX, '\n');
cout << record.address.zip_code << endl;
getline(inFile, record.person.firstName);
cout << record.person.firstName << endl;
return !inFile.fail();
}
CodePudding user response:
The complete working program given below shows how you can achieve what you want. I have done some corrections to your given code snippet. Major changes include using a std::vector
for storing information and also calling readInfo()
and printInfo()
only once instead of calling them again and again in a while loop. Using a vector has the advantage that you can use that vector for later purposes(if any).
#include <iostream>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <string>
#include <climits>
#include <vector>
using namespace std;
struct Person
{
string firstName ;
string lastName;
string phoneNumber;
};
struct Address
{
string streetNum_Name;
string city;
string state;
int zip_code = 70; //always initialize built in type in block/local scope
};
struct Info
{
Person person;
Address address;
};
void printFileHeader(ofstream& outFile);
bool openInputFile(ifstream& inFile);
void openOutputFile(ofstream& outFile);
void readInfo(ifstream& inFile, std::vector<Info>&);
void printInfo(ofstream& outFile, std::vector<Info>&);
int main()
{
ifstream inFile;
ofstream outFile;
bool fileStreamState;
std::vector<Info> infoVec; //this vector will contain all the information
//Info person; //no need for this anymore since we have the vector
//printFileHeader(outFile);//call this after openOutputFile()
fileStreamState = openInputFile(inFile);
openOutputFile(outFile);
printFileHeader(outFile);
cout << "Processing information. Please Wait...." << endl << endl;
readInfo(inFile, infoVec) ; //call readInfo once instead of calling again and again
printInfo(outFile, infoVec);//call printInfo once instead of calling again and again
outFile << setw(7) << "-----" << setw(20) << "---------" << setw(15) << "----------" << setw(20) << "----"
<< setw(12) << "------------" << endl;
cout << "Program has finished execution." << endl;
inFile.close();
outFile.close();
}
void printFileHeader(ofstream& outFile) {
outFile << left << setw(7) << "Entry" << setw(20) << "Last Name" << setw(15) << "First Name" << setw(20) << "City"
<< setw(12) << "Phone Number" << endl;
outFile << setw(7) << "-----" << setw(20) << "---------" << setw(15) << "----------" << setw(20) << "----"
<< setw(12) << "------------" << endl;
}
bool openInputFile(ifstream& inFile) {
string filename;
cout << "Enter the name of the input file: ";
cin >> filename;
cout << filename << endl << endl;
inFile.open(filename.c_str());
while(inFile.fail()) {
cout << string(15,'*') << " File Open Error " << string(15,'*') << endl;
cout << "==> Input file failed to open properly!!\n";
cout << "==> Attempted to open file: " << filename << endl;
cout << "==> Try Again\n";
cout << string(47,'*') << endl<< endl;
inFile.clear();
cout << "Enter in the name of the input file: ";
cin >> filename;
cout << filename << endl << endl;
inFile.open(filename.c_str());
}
return 1;
}
void openOutputFile(ofstream& outFile) {
string filename;
cout << "Enter the name of the output file: ";
cin >> filename;
cout << filename << endl << endl;
outFile.open(filename.c_str());
while(outFile.fail()) {
cout << string(15,'*') << " File Open Error " << string(15,'*') << endl;
cout << "==> Output file failed to open properly!!\n";
cout << "==> Attempted to open file: " << filename << endl;
cout << "==> Try Again\n";
cout << string(47,'*') << endl<< endl;
outFile.clear();
cout << "Enter in the name of the input file: ";
cin >> filename;
cout << filename << endl << endl;
outFile.open(filename.c_str());
}
}
void readInfo(ifstream& inFile, std::vector<Info> &infoVec) {
std::string temporaryZipCode;
Info info;
while(getline(inFile, info.person.phoneNumber,'\n'),
getline(inFile, info.person.lastName,'\n'),
getline(inFile, info.address.streetNum_Name,'\n'),
getline(inFile, info.address.city,'\n'),
getline(inFile, info.address.state,'\n'),
getline(inFile, temporaryZipCode, '\n'),
getline(inFile, info.person.firstName,'\n')
)
{
std::istringstream ss(temporaryZipCode);
ss >> info.address.zip_code;
infoVec.emplace_back(info);
}
}
void printInfo(ofstream& outFile, std::vector<Info> &infoVec) {
int entry = 0; //no need for making it static
for(const Info& record: infoVec )
{
outFile << left << setw(7) << entry << setw(20) << record.person.lastName << setw(15) << record.person.firstName
<< setw(20) << record.address.city << setw(12) << record.person.phoneNumber << endl;
entry ;
}
}
The output of the above program can be seen here. I have added comments wherever i have made changes to your program.