I'm almost finished with this program but the problem I'm having is with freeing the memory I allocated. Particularly in the area where I have pointers to strings.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/////////////// user defined data /////////////////////
struct State
{
char * name; // state name
int year; // year of entry into the union
char * cap; // state capital
int popRank; // population ranking
};
struct Database
{
struct State * list; // array of states
int count; // total count of states
char * filename; // input filename
};
/////////////// function prototypes ////////////////////
struct Database * initDatabase (char * filename);
void deleteDatabase (struct Database * db);
void fillDatabase (struct Database * db);
void insertDatabase (struct Database* db, int index, struct State * state);
void printDatabase (struct Database * db);
int initState (struct State * state, char * name, int year, char * cap, int popRank);
void deleteState (struct State * state);
void copyState (struct State * from, struct State * to);
void printState (struct State * state);
////////////////////////// program start ///////////////////////////////////////
int main(void)
{
struct Database * db;
if (db = initDatabase("states.txt")) // allocate memory for Database struct,
// then initialize fields of Database struct
{
fillDatabase(db); // read from file
printDatabase(db); // print data
deleteDatabase(db); // free memory in Database struct
free(db); // free Database struct itself
return 0;
}
else // not successful
{
return 1;
}
}
////////////////////// Database functions ////////////////////////////////
//initDatabase - allocates memory for Database struct and initializes
// each field
//input: input filename
//return: pointer to Database struct if success
// NULL if fail
struct Database * initDatabase (char * filename)
{
FILE * fpIn;
struct Database * db;
struct State * states;
char * string;
// open input file and check for open success
if ( ( fpIn = fopen( filename, "r" ) ) )
{
// allocate memory for Database struct and check for success
if ( db = ( struct Database * )malloc( sizeof( struct Database ) ) )
{
// allocate memory for filename field and initializes with filename
if ( string = ( char * )malloc( sizeof( char ) * strlen( filename ) ) )
{
strcpy( string, filename );
db->filename = string;
}
else
{
printf("Not enough memory!\n");
exit(0);
}
// initialize count field to 50
db->count = 50;
// initialize list field by allocating memory for array of 50 states
// and check for success
if ( states = ( struct State * )malloc( sizeof( struct State ) * 50 ) )
{
db->list = states;
}
else
{
printf("Not enough memory!\n");
exit(0);
}
}
}
else
{
printf("Error with file!\n");
exit(0);
}
// close input file
fclose( fpIn );
return db;
}
//deleteDatabase - frees allocated memory inside a Database struct
//input: pointer to Database struct
//return: nothing
void deleteDatabase (struct Database * db)
{
while ( db->list )
{
deleteState( db->list );
db->list++;
}
}
//fillDatabase - reads info from file and stores in array of State structs
//input: pointer to Database struct
//return: nothing
void fillDatabase (struct Database * db)
{
struct State tempState; // temp State struct to store data from file
char name[80]; // temp variables
int year; // to store
char cap[80]; // input data
int popRank; // from file
int index = 0; // index into array of State structs
FILE *fpIn;
int cnt;
// open file from filename field of db
// don't need to check for file open success because initDatabase already checked
fpIn = fopen( db->filename, "r" );
// loop through all the states
for ( cnt = 0; cnt < db->count; cnt++ )
{
// read and parse one line of file into 4 input data fields
if ( fscanf( fpIn, "%[^,], %d, %[^,], %d", name, &year, cap, &popRank ) == 4 )
{
// if tempState is created successfully from the 4 input data
if ( initState (&tempState, name, year, cap, popRank) )
{ // then copy tempState data into array of states at the current index
insertDatabase (db, index, &tempState);
}
index++;
}
else
{
printf("Error reading file!\n");
exit(0);
}
}
// close file
fclose( fpIn );
}
//insertDatabase - copy state data from tempState into appropriate place in array
//input: pointer to Database struct
// current index in array
// pointer to tempState containing state data
//return: nothing
void insertDatabase (struct Database * db, int index, struct State * state)
{
// set pCurrent to location to be inserted in array
struct State *pCurrent = db->list + index;
// copy from state to pCurrent
copyState (state, pCurrent);
return;
}
//printDatabase - print data of state array
//input: pointer to Database struct
//return: nothing
void printDatabase (struct Database * db)
{
int i;
printf (" State name Year Capital Pop. rank\n");
printf ("------------------------------------------------\n");
for (i = 0; i < db->count; i++)
printState(db->list+i);
return;
}
//////////////////////// State functions //////////////////////////////
//initState - initializes a State struct with input data
//input: pointer to State struct
// name, year, capital, and population rank of state
//return: true for success
// false for fail
int initState (struct State * state, char * name, int year, char * cap, int popRank)
{
char * stateName;
char * capital;
// if memory allocation is successful, store name
if ( stateName = ( char * )malloc( sizeof( char ) * strlen( name ) ) )
{
strcpy( stateName, name );
state->name = stateName;
}
else
{
printf("Not enough memory!\n");
return 0;
}
// store year
state->year = year;
// if memory allocation is successful, store capital
if ( capital = ( char * )malloc( sizeof( char ) * strlen( cap ) ) )
{
strcpy( capital, cap );
state->cap = capital;
}
else
{
printf("Not enough memory!\n");
return 0;
}
// store population ranking
state->popRank = popRank;
return 1;
}
//deleteState - frees allocated memory inside a State struct
//input: pointer to State struct
//return: nothing
void deleteState (struct State * state)
{
free( state->name );
free( state->cap );
free( state );
}
//copyState - copies contents between two State structs
//input: pointer to source State struct
// pointer to destination State struct
//return: nothing
void copyState (struct State * from, struct State * to)
{
to->name = from->name;
to->year = from->year;
to->cap = from->cap;
to->popRank = from->popRank;
}
//printState - displays State data
//input: pointer to State struct
//return: nothing
void printState (struct State * state)
{
printf ("%-17s%-8d%-18s%2d\n", state->name, state->year, state->cap, state->popRank);
return;
}
The data from the file is read as state, year, capital, and population ranking.