fichier ne se ouvre pas, en cours d'exécution en dehors des résultats de débogage en défaut de seg (c ++)
-
19-09-2019 - |
Question
Bonjour (et merci à l'avance)
Je suis un peu quandry, je ne peux pas l'air de comprendre pourquoi je suis seg la formation de failles.
Quelques notes:
- Il est un cours - et, malheureusement, je suis nécessaire pour utiliser l'utilisation des chaînes C- au lieu de std :: string.
- S'il vous plaît Ne pas fixer mon code (j'apprends l'habitude de cette façon et je garderai vous casser les pieds). S'il vous plaît il suffit de pointer les failles dans ma logique et de proposer une fonction / manière différente.
- Plate-forme: gcc version 4.4.1 sur Suse Linux 11.2 (2.6.31 du noyau)
Voici le 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;
}
}
La solution
Le post précédent choisi la cause probable de la immedate segfault, vous avez besoin INPUT_LINE_MAX_LEN + 1 octets pour stocker l'entrée. Mais dans cette fonction il n'y a aucune raison Nto nouvelle / supprimer en premier lieu, il suffit d'utiliser l'omble userEntry [INPUT_LINE_MAX_LEN + 1]; sur la pile
Notez également que vous avez une fuite de mémoire - la classe d'entrée possède les pointeurs, mais ne les supprime pas. Puisque vous ne copiez pas quoi que ce soit, alors il suffit d'ajouter les déclarations de suppression de cette classe fonctionne.
J'espère que l'intention de ce assigment est d'illustrer juste pourquoi nous évitons nouveau [] / supprimer [] et l'acabit en C ++ moderne. Si cela était un cours Java, ce serait quelque chose de programmation dans AWT 1.0 juste pour démontrer pourquoi il a été remplacé il y a quelques années. Les choses est que beaucoup d'instructeurs sont des instructeurs parce qu'ils peuvent professer d'avoir utilisé C ++ « pour plus de 15 ans. » Plus souvent qu'autrement, triste à dire, cela signifie: « Je vous écris en C ++ comme si elle était 1995. » Pick-up « accéléré C ++ » pour un bon débutants dans C ++ qui utilise les bibliothèques.
Autres conseils
Facile problèmes
Le problème est facile à repérer ici:
cin.getline(userEntry, INPUT_LINE_MAX_LEN, ENTER);
Le premier problème est que si INPUT_LINE_MAX_LEN == 1 alors la ligne est mauvaise.
Cela est facile à fixer changer la déclaration og userEntry à:
userEntry = new char[INPUT_LINE_MAX_LEN + 1];
Le deuxième problème que je vois est:
// GARBAGE COLLECTION
delete[] userEntry;
Ce qui est faux parce que vous attribuez un seul ombles pas un tableau de char pour userEntry. La même solution que ci-dessus.
Une meilleure solution consiste à utiliser un réseau géré de caractères (par exemple une chaîne de caractères)
std::string userEntry;
std::getline(std::cin,userEntry);
Pas besoin d'allouer ou supprimer et redimensionne de manière à vous ne pouvez pas annuler alors fin.
Autres soucis:
Voyant cela dans le code C ++ fait les lièvres sur le dos de mon nech se lever:
typedef void (*WordDefFunc)(const char *word, const char *definition);
En C ++, il est beaucoup plus facile d'utiliser des interfaces plutôt que des pointeurs de fonction. (Oui je sais que C ++ n'a pas l'interface de mot-clé. Mais le concept d'une interface est la même dans toutes les langues est une définition de classe qui met en œuvre un contrat spécifique).
class IFuncAction
{
virtual void action(char const* word,char const* definition) = 0;
};
Vous faites beaucoup trop gestion de la mémoire dans la classe.
Je peux déjà voir plusieurs fuites de mémoire (si je regarde plus je suis sûr que je vais repérer des pointeurs sur des objets non Existant qui sont passés hors de portée).
Un programme moderne C ++ sera très peu pointeurs à l'intérieur.
- Remplacez votre "const char *" et votre "char *" avec std :: string.
- Remplacez vos tableaux créés manuellement avec std :: vector <>
- Oh. Nous avons déjà un dictionnaire standard. Consulter std :: carte.
Je parie que la plupart de vos problèmes disparaitra si vous arrêtez d'essayer de faire la gestion de la mémoire manuelle comme celui-ci était un programme C.
Dictionnaire :: Dectionary
Idéalement, le constructeur dictionnaire woudl ressembler à ceci:
// 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;
}
Vous êtes allocation caractère unique pour l'entrée de l'utilisateur, alors qu'il pourrait être beaucoup plus grand. Utilisez char *userEntry = new char[MAX_PATH]
à la place