The problem I'm having is with overloading the >> operator so that I could read data from a file directly into a class's member data. Everytime I run through the program, it just crashes. when I look through the debugger, it brings me to some page of crazy code.
So far, I've managed to make everything in my program work except just that.
I have no clue why this segment of code won't work.
Atlas::Atlas(char * file)
{
ifstream inputFile(file);
db = new Database(file);
inputFile >> *db; // gives me problems :\
// db->fillDatabase();
inputFile.close();
}
Here's the complete code:
#include <iostream>
#include <cstring>
#include <fstream>
#include "state.h"
#include "database.h"
#include "formatheader.h"
#include "atlas.h"
using std::cout;
using std::cin;
using std::ostream;
////////////////////////// program start ///////////////////////////////////////
int main(void)
{
const int max = 81;
char filename[max];
char stateInput[max];
char name[max];
char cap[max];
int year, popRank;
int index;
Atlas * pA;
//////// set up Atlas object and print its data ////////
cout << "Enter filename or hit ENTER: ";
cin.getline(filename, max);
if ( strlen(filename) == 0)
pA = new Atlas;
else
pA = new Atlas(filename);
cout << *pA; // print information of all states in the database
////// create a state to replace an existing state in the database //////
cout << "Enter new information for state, comma separated: ";
cin.getline(stateInput, max);
Format::parse(stateInput, name, &year, cap, &popRank); // new Format function
State s(name, year, cap, popRank);
cout << "This is the new information for the state: ";
cout << s;
cout << "Enter index of state to be replaced: ";
cin >> index;
cin.ignore(100, '\n');
pA->replace(index, s);
cout << *pA;
// add code you already have in lab 3 to search in the database for
// the new state and print it
// you should print the new state in the database, not the state s above
cout << "Enter state name or press ENTER to stop: ";
cin.getline(stateInput, max);
while ( stateInput[0] )
{
const State foundState = pA->getState( Format::fixString(stateInput) );
if ( strcmp(foundState.getName(), "none") == 0 &&
strcmp(foundState.getCap(), "none") == 0 )
cout << stateInput << " was not found!\n";
else
{
cout << "State: " << Format::upperCase(foundState.getName()) << '\n';
cout << "Year: " << foundState.getYear() << '\n';
cout << "Capital: " << Format::upperCase(foundState.getCap()) << '\n';
cout << "Population Ranking: " << foundState.getPopRank() << '\n';
}
cout << "\nEnter a state name or press ENTER to stop>: ";
cin.getline(stateInput, max);
}
cout << "Have a nice day!\n";
return 0;
}
#ifndef DATABASE_H
#define DATABASE_H
#include "state.h"
using std::ifstream;
class Database
{
public:
Database(char * file = "states.txt");
Database(const Database & arg);
~Database() { delete [] list; delete [] filename; }
int getCount() { return count; }
State * getList() { return list; }
void deleteDatabase ();
void fillDatabase ();
friend ifstream &operator>>(ifstream &in, Database & obj);
private:
State * list; // array of states
int count; // total count of states
char * filename; // input filename
};
#endif
#include <iostream>
#include <cstring>
#include <fstream>
#include "state.h"
#include "database.h"
using std::cout;
using std::cin;
using std::ifstream;
////////////////////// Database functions ////////////////////////////////
// Constructor
Database::Database(char * file) : count(5)
{
// open input file and check for open success
if ( ifstream inputFile(file) )
{
// allocate memory for Database struct and check for success
// allocate memory for filename field and initializes with filename
if ( filename = new char[strlen( file ) + 1] )
strcpy( filename, file );
else
cout << "Not enough memory!" << '\n';
// initialize list field by allocating memory for array of 10 states
// and check for success
if ( list = new State[5] ) {}
else
cout << "Not enough memory!" << '\n';
// close input file
inputFile.close();
}
else
{
cout << "File not found!" << '\n';
exit(0);
}
}
Database::Database(const Database & arg) : count(arg.count)
{
if ( filename = new char[strlen( arg.filename ) + 1] )
strcpy( filename, arg.filename );
else
cout << "Not enough memory!\n";
if ( list = new State[count])
for ( int cnt = 0; cnt < count; cnt++)
list[cnt] = arg.list[cnt];
else
cout << "Not enough memory!\n";
}
//fillDatabase - reads info from file and stores in array of State structs
//input: pointer to Database struct
//return: nothing
void Database::fillDatabase ()
{
char name[80]; // temp variables
int year;
char cap[80]; // input data
int popRank;
char array[100]; // temporary storage for file input
// open file from filename field of db
// don't need to check for file open success because initDatabase already checked
ifstream inputFile( filename );
// loop through all the states
for ( int cnt = 0; cnt < count; cnt++ )
{
// read and parse one line of file into 4 input data fields
if ( !inputFile.eof() )
{
inputFile.getline( array, 100 );
if ( sscanf( array, "%[^,], %d, %[^,], %d", name, &year, cap,
&popRank ) == 4 )
{
// if tempState is created successfully from the 4 input data
State tempState(name, year, cap, popRank);
list[cnt] = tempState;
}
else
{
cout << "Error with file!" << '\n';
return;
}
}
}
// close file
inputFile.close();
}
ifstream &operator>>(ifstream &in, Database & obj)
{
char name[80];
int year;
char cap[80];
int popRank;
char array[100];
ifstream inputFile( in );
for (int cnt = 0; cnt < obj.count; cnt++)
{
if ( !inputFile.eof() )
{
inputFile.getline( array, 100 );
if ( sscanf( array, "%[^,], %d, %[^,], %d", name, &year, cap,
&popRank ) == 4 )
{
State tempState(name, year, cap, popRank);
obj.list[cnt] = tempState;
}
else
cout << "Error with file!" << '\n';
}
}
inputFile.close();
return in;
}
#ifndef STATE_H
#define STATE_H
#include <iostream>
using std::ostream;
class State
{
public:
State(char * tempName = "none", int tempYear = 0, char * tempCap = "none", int tempPopRank = 0);
State( const State & arg );
~State() { delete [] name; delete [] cap; }
int findState(char * stateName) const;
char * getName() const { return name; }
int getYear() const { return year; }
char * getCap() const { return cap; }
int getPopRank() const { return popRank; }
void changeName(char * tempName);
void changeCap(char * tempCap);
void changeYear(int tempYear) { year = tempYear; }
void changePopRank(int tempPopRank) { popRank = tempPopRank; }
// overloaded operators
friend ostream &operator<<(ostream &out, State const & obj);
State & operator=(const State & tempState);
private:
char * name; // state name
int year; // year of entry into the union
char * cap; // state capital
int popRank; // population ranking
};
#endif
#include <iostream>
#include <cstring>
#include "state.h"
using std::cout;
using std::cin;
State::State(char * tempName, int tempYear, char * tempCap, int tempPopRank) : year(tempYear), popRank(tempPopRank)
{
char * stateName;
char * capital;
// if memory allocation is successful, store name
if ( stateName = new char[strlen( tempName ) + 1 ] )
{
strcpy( stateName, tempName );
name = stateName;
}
else
cout << "Not enough memory!" << '\n';
// if memory allocation is successful, store capital
if ( capital = new char[strlen( tempCap ) + 1 ] )
{
strcpy( capital, tempCap );
cap = capital;
}
else
cout << "Not enough memory!" << '\n';
}
State::State( const State & arg ) : year(arg.year), popRank(arg.popRank)
{
name = new char[strlen(arg.name) + 1];
strcpy(name, arg.name);
cap = new char[strlen(arg.cap) + 1];
strcpy(cap, arg.cap);
}
//////////////////////// State functions //////////////////////////////
int State::findState(char * stateName) const
{
if ( strcmp( stateName, name ) == 0 )
return 1;
else
return 0;
}
void State::changeName(char * tempName)
{
name = new char[strlen(tempName) + 1];
strcpy( name, tempName );
}
void State::changeCap(char * tempCap)
{
cap = new char[strlen(tempCap) + 1];
strcpy( cap, tempCap );
}
State &State::operator=(const State & tempState)
{
name = new char[strlen(tempState.name) + 1];
strcpy ( name, tempState.name );
year = tempState.year;
cap = new char[strlen(tempState.cap) + 1];
strcpy( cap, tempState.cap );
popRank = tempState.popRank;
return *this;
}
ostream &operator<<(ostream &out, State const & obj)
{
out << obj.name << ' ';
out << obj.year << ' ';
out << obj.cap << ' ';
out << obj.popRank << '\n';
return out;
}
#ifndef FORMAT_H
#define FORMAT_H
class Format
{
public:
static char * fixString(char * string);
static char * upperCase(char * string);
static void parse(char * input, char * name, int * year, char * cap, int * popRank);
};
#endif
#include <iostream>
#include "formatheader.h"
using std::cout;
char * Format::fixString(char * string)
{
// capitalize the first letter of the sentence
string[0] = toupper( string[0] );
for (int cnt = 1; cnt < (strlen(string) + 1); cnt++)
if ( isalpha( string[cnt] ) )
string[cnt] = tolower( string[cnt] ); // set to lower case
else if ( string[cnt] == ' ' )
{
++cnt; // move to the beginning of the next word
string[cnt] = toupper( string[cnt] ); // capitalize
}
return string;
}
char * Format::upperCase(char * string)
{
for (int cnt = 0; cnt < (strlen(string) + 1); cnt++)
if ( isalpha( string[cnt] ) )
string[cnt] = toupper( string[cnt] );
return string;
}
void Format::parse(char * input, char * name, int * year, char * cap, int * popRank)
{
sscanf( input, "%[^,], %d, %[^,], %d", name, year, cap, popRank );
}
#ifndef ATLAS_H
#define ATLAS_H
#include "database.h"
#include "state.h"
class Atlas
{
public:
Atlas(char * file = "states.txt");
~Atlas() { delete db; }
void replace(int index, State const & s);
State getState(char * stateName) const;
// overloaded operators
friend ostream &operator<<(ostream &, Atlas const & obj);
private:
Database * db;
};
#endif
#include <iostream>
#include <fstream>
#include "atlas.h"
#include "database.h"
#include "state.h"
using std::ifstream;
using std::ios_base;
Atlas::Atlas(char * file)
{
ifstream inputFile(file);
db = new Database(file);
inputFile >> *db;
// db->fillDatabase();
inputFile.close();
}
void Atlas::replace(int index, State const & s)
{
State * tempState = db->getList();
delete [] tempState[index].getName();
delete [] tempState[index].getCap();
tempState[index].changeName(s.getName());
tempState[index].changeYear(s.getYear());
tempState[index].changeCap(s.getCap());
tempState[index].changePopRank(s.getPopRank());
}
State Atlas::getState(char * stateName) const
{
State * tempState = db->getList();
for (int cnt = 0, found = 0; cnt < db->getCount() && !found; cnt++)
found = tempState[cnt].findState( stateName );
if ( found )
return State( tempState[cnt - 1] );
else
return State();
}
ostream &operator<<(ostream &out, Atlas const & obj)
{
out << " State name Year Capital Pop. rank\n";
out << "------------------------------------------------\n";
for (int cnt = 0; cnt < obj.db->getCount(); cnt++)
{
out.setf(ios_base::left);
out.width(17);
out << obj.db->getList()[cnt].getName();
out.setf(ios_base::left);
out.width(8);
out << obj.db->getList()[cnt].getYear();
out.setf(ios_base::left);
out.width(18);
out << obj.db->getList()[cnt].getCap();
out.setf(ios_base::left);
out.width(2);
out << obj.db->getList()[cnt].getPopRank() << '\n';
}
return out;
}