РЕДАКТИРОВАТЬ: Я поместил это изменение вверху, так как оно прямо отвечает на ваш вопрос о том, почему Word не работает. Ваш конструктор копирования неверен:
Word::Word( const Word* theObject )
{
ptr_ = theObject->ptr_;
len_ = theObject->len_;
}
это не делает копию того, на что указывает theObject->ptr_
, только указатель. Таким образом, у вас есть два объекта Word
, указывающих на одну и ту же внутреннюю строку. Это очень плохо, когда объект Word удаляется. Правильная реализация (с использованием техник, которые вы применили, я рекомендую против них) была бы такой:
Word::Word( const Word* theObject )
{
ptr_ = new char[theObject->len_ + 1 ];
strcpy( ptr_, theObject->ptr_ );
len_ = theObject->len_;
}
РЕДАКТИРОВАТЬ: Earwicker также отметил следующее:
... хотя этот "конструктор копирования"
не является конструктором копирования. Итак
генерируемый компилятором
существует, и делает то же самое для каждого члена
копировать, и, следовательно, та же проблема
все еще существует.
Чтобы исправить это, вам нужно создать правильный конструктор копирования, который должен иметь прототип:
Word::Word(const Word &theObject);
Также этот код здесь:
while ( !inFile.eof() )
{
inFile >> str;
wrdCount++;
g_wordArray = new Word *[wrdCount];
}
течет как сито! Вы перераспределяете g_wordArray
после каждого прочитанного слова и полностью забываете удалить предыдущее. Я еще раз покажу разумную реализацию, используя методы, которые вы пытаетесь использовать.
while (inFile >> str)
{
inFile >> str;
wrdCount++;
}
g_wordArray = new Word *[wrdCount];
Обратите внимание на то, как он считает слова, затем выделяет место один раз , после того, как знает, сколько выделить. Теперь g_wordArray
готов к использованию для wrdCount
объектов слова.
ОРИГИНАЛЬНЫЙ ОТВЕТ:
почему бы вам просто не заменить класс Word
на std::string
? Это сделало бы код намного меньше и с ним легче работать.
Если вам будет проще, просто сделайте это:
typedef std::string Word;
тогда вы можете сделать так:
Word word("hello");
char first_char = word[0];
плюс к этому добавлен бонус, исключающий необходимость использования члена .c_str()
для получения строки в стиле c.
EDIT:
Я бы тоже изменил ваш g_wordArray
на std::vector<Word>
. Таким образом, вы можете просто сделать это:
g_wordArray.push_back(Word(str));
больше нет динамического распределения! это все сделано для тебя. Размер массива слов будет ограничен только объемом вашей оперативной памяти, поскольку std::vector
увеличивается по мере необходимости при использовании push_back()
.
Кроме того, если вы сделаете это ... угадайте, что для подсчета слов вы просто сделаете это:
g_wordArray.size();
нет необходимости вручную отслеживать их количество!
EDIT:
Также этот код не работает:
while( !inFile2.eof() )
{
inFile2 >> str2;
...
}
, поскольку eof не установлен до после попытки чтения, вам лучше использовать этот шаблон:
while(inFile2 >> str2)
{
...
}
, который правильно остановится на EOF.
Суть в том, что если вы все сделаете правильно, фактического кода, который вам нужно написать, должно быть очень мало.
EDIT:
Вот пример прямой реализации того, что, я думаю, вы хотите. Из пунктов меню кажется, что пользователь должен сначала выбрать опцию «a», затем «b» ноль или более раз, чтобы отфильтровать некоторые слова, а затем, наконец, c, чтобы напечатать результаты (по одному слову в строке). Кроме того, опция 'D' на самом деле не нужна, поскольку нажатие Ctrl+D
отправляет EOF программе и приводит к сбою теста "while(std::cin >> option)
". Таким образом, окончание программы. (По крайней мере, в моей ОС это может быть Ctrl + Z` для Windows).
Также он не прикладывает усилий (как и ваши) к пунктуации, но вот он:
#include <string>
#include <vector>
#include <fstream>
#include <iostream>
#include <algorithm>
#include <functional>
#include <iterator>
struct starts_with : public std::binary_function<std::string, char, bool> {
bool operator()(const std::string &s, char ch) const {
return s[0] == ch;
}
};
void print_prompt() {
std::cout << "Please make a selection: \na) Read a text file\nb) Remove words starting with letter\nc) Print words to console" << std::endl;
}
int main( const int argc, const char **argv) {
std::vector<std::string> file_words;
char option;
print_prompt();
while(std::cin >> option) {
switch(option) {
case 'a':
case 'A':
std::cout << "Enter a file name: ";
// scope so we can have locals declared
{
std::string filename;
std::string word;
std::cin >> filename;
int word_count = 0;
std::ifstream file(filename.c_str());
while(file >> word) {
file_words.push_back(word);
}
std::cout << file_words.size() << " Words read from the file " << std::endl;
}
break;
case 'b':
case 'B':
// scope so we can have locals declared
{
std::cout << "Enter letter to filter: ";
char letter;
std::cin >> letter;
// remove all words starting with a certain char
file_words.erase(std::remove_if(file_words.begin(), file_words.end(), std::bind2nd(starts_with(), letter)), file_words.end());
}
break;
case 'c':
case 'C':
// output each word to std::cout separated by newlines
std::copy(file_words.begin(), file_words.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
break;
}
print_prompt();
}
return 0;
}