لا يفتح الملف، يعمل خارج مصحح الأخطاء في خطأ SEG (C ++)

StackOverflow https://stackoverflow.com/questions/2441882

سؤال

مرحبا (وشكرا مقدما)

أنا في القليل من القانق، لا أستطيع أن أبدو لمعرفة سبب خلط.

بضعة ملاحظات:

  1. إنه في الدورة التدريبية - والأسف، أنا مطلوبة لاستخدام استخدام C-Strings بدلا من STD :: String.
  2. من فضلك لا إصلاح التعليمات البرمجية الخاصة بي (لن أتعلم بهذه الطريقة وسوف أظل تنقلك). الرجاء الإشارة فقط إلى العيوب في منطقتي واقترح وظيفة / طريقة مختلفة.
  3. منصة: دول مجلس التعاون الخليجي الإصدار 4.4.1 على SUSE Linux 11.2 (2.6.31 Kernel)

إليك الرمز

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;
      }
}
هل كانت مفيدة؟

المحلول

التقط المنشور السابق السبب الأرجح الأرجح ل Segfault، تحتاج إلى Input_Line_max_len + 1 بايت لتخزين المدخلات. ولكن في هذه الوظيفة لا يوجد سبب NTO جديد / حذف في المقام الأول، فقط استخدم Char Userentry [Input_Line_max_len + 1]؛ على المكدس

لاحظ أيضا أن لديك تربيس ذاكرة - فئة الإدخال يمتلك المؤشرات، ولكن لا يحذفها. نظرا لأنك لا نسخ أي شيء، فما عليك سوى إضافة بيانات حذف إلى هذه الفئة.

آمل أن توضح نية هذا الاعتماد فقط لماذا نتجنب [] / حذف جديد [] و ILK في C ++ الحديثة. إذا كانت هذه دورة Java، فسيكون ذلك مثل برمجة شيء ما في AWT 1.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 ل userentry. الحل نفسه على النحو الوارد أعلاه.

الحل الأفضل هو استخدام مجموعة من الأحرف المدارة (أي سلسلة)

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

لا حاجة إلى تخصيص أو حذف وأعاد أحجامها كما هو مطلوب حتى لا تتمكن من الشطب ثم تنتهي.

مخاوف أخرى:

رؤية هذا في كود C ++ يجعل الأرانب على الجزء الخلفي من My Nech Stand Up:

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 :: Vector <>
  • أوه. لدينا بالفعل قاموس قياسي. ابحث عن STD :: MAP.

سأراهن أن معظم مشاكلك سوف تختفي إذا توقفت عن محاولة إجراء إدارة الذاكرة اليدوية مثل هذا البرنامج ج.

قاموس :: Decrectary.

من الناحية المثالية قام القاموس منشئ 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