你好(并在此先感谢)

我在一点一quandry,我似乎找出为什么我seg故障。

几个注:

  1. 这是一门课程--并且可悲的是我 需要使用利用C-串 而不是std::string.
  2. 请不要解决我的代码(我不会了解的方式和我会继续窃听您)。请指出的缺陷,在我的逻辑,并建议一个不同的功能。
  3. 平台:海湾合作委员会的版本4.4.1在Suse Linux11.2(2.6.31核)

这里的代码

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
  }
*/

项。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;
      }
}
有帮助吗?

解决方案

以前的岗位挑选出来的有可能immedate导致出现段错误,需要INPUT_LINE_MAX_LEN+1bytes储存的输入。但是,在这个功能没有任何理由nto新删除在第一个地方,就使用char userEntry[INPUT_LINE_MAX_LEN+1];在栈

还注意到,你有一个内存泄漏--入门级拥有指针,但并不将它们删除。因为你不是复制任何东西,然后就加入该删除发言到此类会的工作。

我希望,本assigment是为了说明只是为什么我们避免新的[]/删除[]和同类在现代C++。如果这是一个Java然,这会像编程东西在AWT1.0只是证明为什么它取代多年前。事情是,许多教师是讲师,因为他们可以自称有使用C++"为15年以上。" 往往不遗憾地说,这意味着"我写C++如果它是1995年。" 拿起"加速C++"一个良好的初学者进C++,使用的图书馆。

其他提示

简单的问题

简单问题来发现是在这里:

cin.getline(userEntry,  INPUT_LINE_MAX_LEN,  ENTER); 

第一个问题是,除非INPUT_LINE_MAX_LEN==1然后是错误的。
这是易于修改《宣言》og userEntry:

userEntry = new char[INPUT_LINE_MAX_LEN + 1];

第二个问题,我看到的是:

// GARBAGE COLLECTION   
delete[] userEntry; 

这是错误的,因为你只配一个单char不一系列char userEntry.同样的解决方案如上。

一个更好的解决方案是以使用管理的阵列的字符的(即一串)

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

没有必要分配或删除,并重新尺寸要求的所以你不能写下来然后结束。

其他的忧虑:

看到这C++码使得野兔在我nech站起来:

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

C++它更便于使用的接口,而不是功能的指针。(是的,我知道C++没有关键字接口。但是该概念的一个接口是一样的,在所有的语言,它是一类定义中,实现了一具体合同)。

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

你做了太多的管理内存在类。
我已经可以看到几内存渗漏(如果我看很难,我肯定我会当场指不存在对象已经出的范围).

一个现代C++的程序将有很少的指针。

  • 取代你的"const char*"和你"char*"与std::string.
  • 取代你的手创建的阵列标准::矢量<>
  • 哦。我们已经有一个标准的字典。看起来std::图。

我打赌您的大多数问题将消失,如果你停止试图做手册管理存储器像这是C节目。

字典::Dectionary

最理想的词典构造woudl是这样的:

// 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;
} 

你被分配的单字用户进入,而这可能是一个很大。使用 char *userEntry = new char[MAX_PATH] 而不是

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top