Frage

Hallo (und Dank im Voraus)

Ich bin in ein bisschen ein quandry, kann ich nicht scheinen, um herauszufinden, warum ich Verwerfungen bin seg.

Ein paar Anmerkungen:

  1. Es ist für einen Kurs - und leider bin ich erforderlich ist, um den Einsatz C-Strings zu verwenden anstelle von std :: string.
  2. Bitte nicht meinen Code beheben (Ich werde nicht auf diese Weise lernen, und ich halten Sie nerve). Sie weisen darauf hin, nur die Fehler in meiner Logik und schlägt eine andere Funktion / Art und Weise.
  3. Plattform: gcc Version 4.4.1 auf Suse Linux 11.2 (Kernel 2.6.31)

Hier ist der 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;
      }
}
War es hilfreich?

Lösung

Der vorherige Eintrag ausgesucht, die wahrscheinlich immedate Ursache des segfault, müssen Sie INPUT_LINE_MAX_LEN + 1 Byte, um die Eingabe zu speichern. Aber in dieser Funktion gibt es keinen Grund nto neu / löschen in erster Linie nur die Verwendung char Userentry [INPUT_LINE_MAX_LEN + 1]; auf dem Stapel

Beachten Sie auch, dass Sie ein Speicherleck zu tun haben - die Eintragsklasse die Zeiger besitzt, sich aber nicht löschen. Da Sie nichts kopieren, dann das Hinzufügen nur die Delete-Anweisungen zu dieser Klasse arbeiten.

Ich hoffe, dass die Absicht dieses assigment zu illustrieren ist nur, warum wir vermeiden new [] / delete [] und die ILK in der modernen C ++. Wenn dies ein Kurs Java, würde dies wie Programmierung, etwas in AWT 1.0 nur zu zeigen, warum es Jahre ersetzt wurde vor. Die Dinge sind, dass viele Lehrer Lehrer sind, weil sie gebraucht C haben bekennen ++ „für mehr als 15 Jahre.“ Mehr als oft nicht, traurig das bedeutet zu sagen: „Ich schreibe C ++, als ob es 1995 war“ Pick up „Accelerated C ++“ für einen guten Anfänger in C ++, dass die Bibliotheken verwendet.

Andere Tipps

Einfache Probleme

Das einfache Problem vor Ort ist hier:

cin.getline(userEntry,  INPUT_LINE_MAX_LEN,  ENTER); 

Das erste Problem ist, dass es sei denn, INPUT_LINE_MAX_LEN == 1 dann die Zeile falsch ist.
Dies ist leicht zu beheben Änderung der Erklärung og Userentry zu:

userEntry = new char[INPUT_LINE_MAX_LEN + 1];

Das zweite Problem, das ich sehe, ist:

// GARBAGE COLLECTION   
delete[] userEntry; 

Welche falsch ist, weil Sie nur ein einziges Zeichen nicht ein Array von char für Userentry zuordnen. Die gleiche Lösung wie oben.

Eine bessere Lösung ist es, eine verwaltete Array von Zeichen zu verwenden (d.h. eine Saite)

std::string    userEntry;
std::getline(std::cin,userEntry);

Keine Notwendigkeit zuzuordnen oder zu löschen und es erneut Größen je nach Bedarf, so dass Sie nicht abschreiben können dann enden.

Andere Sorgen:

Bei diesem Anblick in C ++ Code macht die Hasen auf der Rückseite meines nech aufstehen:

typedef void  (*WordDefFunc)(const char  *word, const char  *definition); 

In C ++ ist es viel einfacher zu bedienenden Benutzeroberflächen eher als Funktionszeiger. (Ja, ich weiß, C ++ nicht das Schlüsselwort-Schnittstelle hat. Aber das Konzept einer Schnittstelle ist das gleiche in allen Sprachen eine Klassendefinition ist, dass implementiert ein bestimmte Vertrag).

class IFuncAction
{
    virtual void action(char const* word,char const* definition) = 0;
};

Sie tun viel zu viel Speicher-Management in der Klasse.
Ich kann schon mehrere Speicherlecks sehen (wenn ich sehe härter ich bin sicher, dass ich Zeiger auf nicht existente Objekte erkennen, die von Rahmen hinausgegangen sind).

Ein modernes C ++ Programm wird nur sehr wenige Hinweise in ihm haben.

  • Ersetzen Sie "const char *" und Ihr "char *" mit std :: string.
  • Ersetzen Sie manuell erstellt Arrays mit std :: vector <>
  • Oh. Wir haben bereits einen Standard-Wörterbuch. Nachschlagen std :: map.

werde ich die meisten Ihrer Probleme wetten disapear, wenn Sie manuelle Speicherverwaltung zu tun aufhören zu versuchen, wie dies ein C-Programm war.

Wörterbuch :: Dectionary

Im Idealfall das Wörterbuch Konstruktor woudl wie folgt aussehen:

// Pass a stream to the constructor.
// Now a dictionary can be created from a file or
// a string (stringstream) when doing unit tests.
//
Dictionary::Dictionary(std::istream& data) 
{
    if (!data)
    {    throw MyProblemException("Bad Input to Dictionary constructor");
    }

    Entry  item;

    // While we can read data from the stream
    while(data >> item)
    {
        // Add it to the store
        m_DictEntry.push_back(item);
    }
} 

std::istream& operator>>(std::istream& str,Entry& data)
{
    std::getline(str,data.m_word, COMMA);
    std::getline(str,data.m_definition);

    return str;
} 

Sie sind Zuteilung einzelnes Zeichen für die Benutzereingabe, während es viel größer sein könnte. Verwenden char *userEntry = new char[MAX_PATH] statt

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top