Hello (and thanks in advance)
I'm in a bit of a quandry, I cant seem to figure out why I'm seg faulting.
A couple of notes:
It's for a course -- and sadly I am
required to use use C-strings
instead of std::string.
Please dont fix my code (I wont learn that way and I will keep bugging you).
please just point out the flaws in my logic and suggest a different function/way.
platform: gcc version 4.4.1 on Suse
Linux 11.2 (2.6.31 kernel)
Here's the code
main.cpp:
// ///////////////////////////////////////////////////////////////////////////////////
// INCLUDES (C/C++ Std Library)
#include <cstdlib> /// EXIT_SUCCESS, EXIT_FAILURE
#include <iostream> /// cin, cout, ifstream
#include <cassert> /// assert
// ///////////////////////////////////////////////////////////////////////////////////
// DEPENDENCIES (custom header files)
#include "dict.h" /// Header for the dictionary class
// ///////////////////////////////////////////////////////////////////////////////////
// PRE-PROCESSOR CONSTANTS
#define ENTER '\n' /// Used to accept new lines, quit program.
#define SPACE ' ' /// One way to end the program
// ///////////////////////////////////////////////////////////////////////////////////
// CUSTOM DATA TYPES
/// File Namespace -- keep it local
namespace
{
/// Possible program prompts to display for the user.
enum FNS_Prompts
{
fileName_, /// prints out the name of the file
noFile_, /// no file was passed to the program
tooMany_, /// more than one file was passed to the program
noMemory_, /// Not enough memory to use the program
usage_, /// how to use the program
word_, /// ask the user to define a word.
notFound_, /// the word is not in the dictionary
done_, /// the program is closing normally
};
}
// ///////////////////////////////////////////////////////////////////////////////////
// Namespace
using namespace std; /// Nothing special in the way of namespaces
// ///////////////////////////////////////////////////////////////////////////////////
// FUNCTIONS
/** prompt() prompts the user to do something, uses enum Prompts for parameter.
*/
void prompt(FNS_Prompts msg /** determines the prompt to use*/)
{
switch(msg)
{
case fileName_ :
{
cout << ENTER << ENTER << "The file name is: ";
break;
}
case noFile_ :
{
cout << ENTER << ENTER << "...Sorry, a dictionary file is needed. Try again." << endl;
break;
}
case tooMany_ :
{
cout << ENTER << ENTER << "...Sorry, you can only specify one dictionary file. Try again." << endl;
break;
}
case noMemory_ :
{
cout << ENTER << ENTER << "...Sorry, there isn't enough memory available to run this program." << endl;
break;
}
case usage_ :
{
cout << "USAGE:" << endl
<< " lookup.exe [dictionary file name]" << endl << endl;
break;
}
case done_ :
{
cout << ENTER << ENTER << "like Master P says, \"Word.\"" << ENTER << endl;
break;
}
case word_ :
{
cout << ENTER << ENTER << "Enter a word in the dictionary to get it's definition." << ENTER
<< "Enter \"?\" to get a sorted list of all words in the dictionary." << ENTER
<< "... Press the Enter key to quit the program: ";
break;
}
case notFound_ :
{
cout << ENTER << ENTER << "...Sorry, that word is not in the dictionary." << endl;
break;
}
default :
{
cout << ENTER << ENTER << "something passed an invalid enum to prompt(). " << endl;
assert(false); /// something passed in an invalid enum
}
}
}
/** useDictionary() uses the dictionary created by createDictionary
* - prompts user to lookup a word
* - ends when the user enters an empty word
*/
void useDictionary(Dictionary &d)
{
char *userEntry = new char; /// user's input on the command line
if( !userEntry ) // check the pointer to the heap
{ cout << ENTER << MEM_ERR_MSG << endl; exit(EXIT_FAILURE);
}
do
{
prompt(word_);
// test code
cout << endl << "----------------------------------------" << endl
<< "Enter something: ";
cin.getline(userEntry, INPUT_LINE_MAX_LEN, ENTER);
cout << ENTER << userEntry << endl;
}while ( userEntry[0] != NIL && userEntry[0] != SPACE );
// GARBAGE COLLECTION
delete[] userEntry;
}
/** Program Entry
* Reads in the required, single file from the command prompt.
* - If there is no file, state such and error out.
* - If there is more than one file, state such and error out.
* - If there is a single file:
* - Create the database object
* - Populate the database object
* - Prompt the user for entry
* main() will return EXIT_SUCCESS upon termination.
*/
int main(int argc, /// the number of files being passed into the program
char *argv[] /// pointer to the filename being passed into tthe program
)
{
// EXECUTE
/* Testing code * /
char tempFile[INPUT_LINE_MAX_LEN] = {NIL};
cout << "enter filename: ";
cin.getline(tempFile, INPUT_LINE_MAX_LEN, '\n');
*/
// uncomment after successful debugging
if(argc <= 1)
{
prompt(noFile_); prompt(usage_);
return EXIT_FAILURE; /// no file was passed to the program
}
else if(argc > 2)
{
prompt(tooMany_); prompt(usage_);
return EXIT_FAILURE; /// more than one file was passed to the program
}
else
{
prompt(fileName_); cout << argv[1]; // print out name of dictionary file
if( !argv[1] )
{
prompt(noFile_); prompt(usage_);
return EXIT_FAILURE; /// file does not exist
}
/*
file.open( argv[1] ); // open file
numEntries >> in.getline(file); // determine number of dictionary objects to create
file.close(); // close file
Dictionary[ numEntries ](argv[1]); // create the dictionary object
*/
// TEMPORARY FILE FOR TESTING!!!!
//Dictionary scrabble(tempFile);
Dictionary scrabble(argv[1]); // creaate the dicitonary object
//*/
useDictionary(scrabble); // prompt the user, use the dictionary
}
// exit
return EXIT_SUCCESS; /// terminate program.
}
Dict.h/.cpp
#ifndef DICT_H
#define DICT_H
// ///////////////////////////////////////////////////////////////////////////////////
// DEPENDENCIES (Custom header files)
#include "entry.h" /// class for dictionary entries
// ///////////////////////////////////////////////////////////////////////////////////
// PRE-PROCESSOR MACROS
#define INPUT_LINE_MAX_LEN 256 /// Maximum length of each line in the dictionary file
class Dictionary
{
public :
//
// Do NOT modify the public section of this class
//
typedef void (*WordDefFunc)(const char *word, const char *definition);
Dictionary( const char *filename );
~Dictionary();
const char *lookupDefinition( const char *word );
void forEach( WordDefFunc func );
private :
//
// You get to provide the private members
//
// VARIABLES
int m_numEntries; /// stores the number of entries in the dictionary
Entry *m_DictEntry_ptr; /// points to an array of class Entry
// Private Functions
};
#endif
-----------------------------------
// ///////////////////////////////////////////////////////////////////////////////////
// INCLUDES (C/C++ Std Library)
#include <iostream> /// cout, getline
#include <fstream> // ifstream
#include <cstring> /// strchr
// ///////////////////////////////////////////////////////////////////////////////////
// DEPENDENCIES (custom header files)
#include "dict.h" /// Header file required by assignment
//#include "entry.h" /// Dicitonary Entry Class
// ///////////////////////////////////////////////////////////////////////////////////
// PRE-PROCESSOR MACROS
#define COMMA ',' /// Delimiter for file
#define ENTER '\n' /// Carriage return character
#define FILE_ERR_MSG "The data file could not be opened. Program will now terminate."
#pragma warning(disable : 4996) /// turn off MS compiler warning about strcpy()
// ///////////////////////////////////////////////////////////////////////////////////
// Namespace reference
using namespace std;
// ///////////////////////////////////////////////////////////////////////////////////
// PRIVATE MEMBER FUNCTIONS
/**
* Sorts the dictionary entries.
*/
/*
static void sortDictionary(?)
{
// sort through the words using qsort
}
*/
/** NO LONGER NEEDED??
* parses out the length of the first cell in a delimited cell
* /
int getWordLength(char *str /// string of data to parse
)
{
return strcspn(str, COMMA);
}
*/
// ///////////////////////////////////////////////////////////////////////////////////
// PUBLIC MEMBER FUNCTIONS
/** constructor for the class
* - opens/reads in file
* - creates initializes the array of member vars
* - creates pointers to entry objects
* - stores pointers to entry objects in member var
* - ? sort now or later?
*/
Dictionary::Dictionary( const char *filename )
{
// Create a filestream, open the file to be read in
ifstream dataFile(filename, ios::in );
/*
if( dataFile.fail() )
{ cout << FILE_ERR_MSG << endl; exit(EXIT_FAILURE);
}
*/
if( dataFile.is_open() )
{
// read first line of data
// TEST CODE in.getline(dataFile, INPUT_LINE_MAX_LEN) >> m_numEntries;
// TEST CODE char temp[INPUT_LINE_MAX_LEN] = {NIL};
// TEST CODE dataFile.getline(temp,INPUT_LINE_MAX_LEN,'\n');
dataFile >> m_numEntries; /** Number of terms in the dictionary file
* \todo find out how many lines in the file, subtract one, ingore first line
*/
//create the array of entries
m_DictEntry_ptr = new Entry[m_numEntries];
// check for valid memory allocation
if( !m_DictEntry_ptr )
{ cout << MEM_ERR_MSG << endl; exit(EXIT_FAILURE);
}
// loop thru each line of the file, parsing words/def's and populating entry objects
for(int EntryIdx = 0; EntryIdx < m_numEntries; ++EntryIdx)
{
// VARIABLES
char *tempW_ptr; /// points to a temporary word
char *tempD_ptr; /// points to a temporary def
char *w_ptr; /// points to the word in the Entry object
char *d_ptr; /// points to the definition in the Entry
int tempWLen; /// length of the temp word string
int tempDLen; /// length of the temp def string
char tempLine[INPUT_LINE_MAX_LEN] = {NIL}; /// stores a single line from the file
// EXECUTE
// getline(dataFile, tempLine) // get a "word,def" line from the file
dataFile.getline(tempLine, INPUT_LINE_MAX_LEN); // get a "word,def" line from the file
// Parse the string
tempW_ptr = tempLine; // point the temp word pointer at the first char in the line
tempD_ptr = strchr(tempLine, COMMA); // point the def pointer at the comma
*tempD_ptr = NIL; // replace the comma with a NIL
++tempD_ptr; // increment the temp def pointer
// find the string lengths... +1 to account for terminator
tempWLen = strlen(tempW_ptr) + 1;
tempDLen = strlen(tempD_ptr) + 1;
// Allocate heap memory for the term and defnition
w_ptr = new char[ tempWLen ];
d_ptr = new char[ tempDLen ];
// check memory allocation
if( !w_ptr && !d_ptr )
{ cout << MEM_ERR_MSG << endl; exit(EXIT_FAILURE);
}
// copy the temp word, def into the newly allocated memory and terminate the strings
strcpy(w_ptr,tempW_ptr); w_ptr[tempWLen] = NIL;
strcpy(d_ptr,tempD_ptr); d_ptr[tempDLen] = NIL;
// set the pointers for the entry objects
m_DictEntry_ptr[ EntryIdx ].setWordPtr(w_ptr);
m_DictEntry_ptr[ EntryIdx ].setDefPtr(d_ptr);
}
// close the file
dataFile.close();
}
else
{ cout << ENTER << FILE_ERR_MSG << endl; exit(EXIT_FAILURE);
}
}
/**
* cleans up dynamic memory
*/
Dictionary::~Dictionary()
{
delete[] m_DictEntry_ptr; /// thou shalt not have memory leaks.
}
/**
* Looks up definition
*/
/*
const char *lookupDefinition( const char *word )
{
// print out the word ---- definition
}
*/
/**
* prints out the entire dictionary in sorted order
*/
/*
void forEach( WordDefFunc func )
{
// to sort before or now.... that is the question
}
*/
Entry.h/cpp
#ifndef ENTRY_H
#define ENTRY_H
// ///////////////////////////////////////////////////////////////////////////////////
// INCLUDES (C++ Std lib)
#include <cstdlib> /// EXIT_SUCCESS, NULL
// ///////////////////////////////////////////////////////////////////////////////////
// PRE-PROCESSOR MACROS
#define NIL '\0' /// C-String terminator
#define MEM_ERR_MSG "Memory allocation has failed. Program will now terminate."
// ///////////////////////////////////////////////////////////////////////////////////
// CLASS DEFINITION
class Entry
{
public:
Entry(void) : m_word_ptr(NULL), m_def_ptr(NULL) { /* default constructor */ };
void setWordPtr(char *w_ptr); /// sets the pointer to the word - only if the pointer is empty
void setDefPtr(char *d_ptr); /// sets the ponter to the definition - only if the pointer is empty
/// returns what is pointed to by the word pointer
char getWord(void) const { return *m_word_ptr; }
/// returns what is pointed to by the definition pointer
char getDef(void) const { return *m_def_ptr; }
private:
char *m_word_ptr; /** points to a dictionary word */
char *m_def_ptr; /** points to a dictionary definition */
};
#endif
--------------------------------------------------
// ///////////////////////////////////////////////////////////////////////////////////
// DEPENDENCIES (custom header files)
#include "entry.h" /// class header file
// ///////////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS
/*
* only change the word member var if it is in its initial state
*/
void Entry::setWordPtr(char *w_ptr)
{
if(m_word_ptr == NULL)
{ m_word_ptr = w_ptr;
}
}
/*
* only change the def member var if it is in its initial state
*/
void Entry::setDefPtr(char *d_ptr)
{
if(m_def_ptr == NULL)
{ m_word_ptr = d_ptr;
}
}