файл не открывается, запуск вне отладчика приводит к ошибке сегмента (c ++) - PullRequest
0 голосов
/ 14 марта 2010

Привет (и заранее спасибо)

Я в некотором затруднении, кажется, я не могу понять, почему я ошибаюсь.

Пара заметок:

  1. Это для курса - и, к сожалению, я требуется использовать использовать C-строки вместо std :: string.
  2. Пожалуйста, не исправляйте мой код (я не научусь так, и буду продолжать вас беспокоить). пожалуйста, просто укажите на недостатки в моей логике и предложите другую функцию / способ.
  3. платформа: gcc версия 4.4.1 на Suse Linux 11.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
  }
*/

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

Ответы [ 3 ]

2 голосов
/ 14 марта 2010

Легкие проблемы

Легкая проблема для определения здесь:

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; 

Что неверно, потому что вы выделяете только один символ, а не массив символов для userEntry. То же решение, что и выше.

Лучшее решение состоит в том, чтобы использовать управляемый массив символов (то есть строку)

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

Нет необходимости выделять или удалять, и он изменяет размеры по мере необходимости, поэтому вы не можете списать их, а затем завершить.

Другие заботы:

Видя это в коде C ++, вырастают зайцы на спине моего nech:

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

В C ++ гораздо проще использовать интерфейсы, чем указатели на функции. (Да, я знаю, что в C ++ нет ключевого слова interface. Но концепция интерфейса одинакова во всех языках, это определение класса, реализующее конкретный контракт).

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

Вы слишком много занимаетесь управлением памятью в классе.
Я уже вижу несколько утечек памяти (если я выгляжу усерднее, я уверен, что укажу указатели на несуществующие объекты, которые вышли из области видимости).

В современной программе на С ++ очень мало указателей.

  • Замените ваш "const char *" и ваш "char *" на std :: string.
  • Замените созданные вручную массивы на std :: vector <>
  • О. У нас уже есть стандартный словарь. Посмотри std :: map.

Бьюсь об заклад, большинство ваших проблем исчезнет, ​​если вы перестанете пытаться выполнять ручное управление памятью, как это было в программе на Си.

Словарь :: Dectionary

В идеале конструктор словаря должен выглядеть так:

// 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;
} 
0 голосов
/ 14 марта 2010

В предыдущем посте была выбрана вероятная непосредственная причина ошибки, вам нужно INPUT_LINE_MAX_LEN + 1 байт для хранения ввода.Но в этой функции нет никаких оснований для нового / удаления в первую очередь, просто используйте char userEntry [INPUT_LINE_MAX_LEN + 1];в стеке

Также обратите внимание, что у вас есть утечки памяти - класс Entry владеет указателями, но не удаляет их.Поскольку вы ничего не копируете, то просто добавление операторов удаления в этот класс будет работать.

Я надеюсь, что цель этого задания - проиллюстрировать, почему мы избегаем new [] / delete [] и тому подобногов современном C ++.Если бы это был курс по Java, это было бы похоже на программирование чего-либо в AWT 1.0 только для того, чтобы продемонстрировать, почему его заменили несколько лет назад.Дело в том, что многие инструкторы являются инструкторами, потому что они могут заявить, что использовали C ++ «более 15 лет».К сожалению, чаще всего это означает «я пишу на C ++, как будто это был 1995 год».Подберите "Ускоренный C ++" для хороших новичков в C ++, который использует библиотеки.

0 голосов
/ 14 марта 2010

Вы выделяете один символ для входа пользователя, хотя он может быть намного больше Используйте char *userEntry = new char[MAX_PATH] вместо

...