这是代码的规范: 您将使用下面定义的Word和Dictionary类,并编写所有成员函数和任何必要的支持函数以达到指定的结果。
Word类应为要存储在字典中的每个单词动态分配内存。
Dictionary类应包含一个指向Word的指针数组。该阵列的内存必须动态分配。您将不得不从文件中读取单词。由于您不知道“ word”文件的大小,因此您不知道分配指针数组的大小。您应该在读取文件时让它动态增长。从数组大小8开始,当该数组被填充时,将数组大小加倍,将原始的8个单词复制到新数组中并继续。
您可以假设“ word”文件已排序,因此您的Dictionary :: find()函数必须包含二进制搜索算法。您可能需要将此要求保存下来,以便以后使用-直到程序的其余部分运行为止。
确保在字典中将单词存储为小写,并将输入文本转换为相同的大小写-这样,即使Dictionary :: find()函数存储为“四个”,它也会成功找到“四个” ”在您的字典中。
到目前为止,这是我的代码。
#include <cstring>
#include <iostream>
#include <fstream>
using namespace std;
class Word
{
char* word_;
public:
Word(const char* text = 0);
~Word() { delete[] word_; word_ = nullptr; }
const char* word() const;
};
Word::Word(const char* arg)
: word_(new char[strlen(arg) + 1])
{
strcpy(word_, arg);
}
const char* Word::word() const
{
return word_;
}
class Dictionary
{
Word** words_;
unsigned int capacity_; // max number of words Dictionary can hold
unsigned int numberOfWordsInDictionary_;
void resize() {
capacity_ = capacity_ * 2;
cout << "Size = " << capacity_ << endl;
};
void addWordToDictionary(char* word) { words_ += *word; };
public:
Dictionary(const char* filename);
~Dictionary() {
delete[] words_; words_ = nullptr;
};
bool find(const char* word);
};
Dictionary::Dictionary(const char * filename)
: words_(new Word*[8]), capacity_(8), numberOfWordsInDictionary_(0)
{
ifstream fin(filename);
if (!filename) {
cout << "Failed to open file!" << endl;
}
char buffer[32];
while (fin.getline(buffer, sizeof(buffer)))
{
if (numberOfWordsInDictionary_ == capacity_)
{
resize();
}
addWordToDictionary(buffer);
}
}
bool Dictionary::find(const char * left)
{
int last = capacity_ - 1,
first = 0,
middle;
bool found = false;
while (!found && first <= last) {
middle = (first + last) / 2;
if (strcmp(left, reinterpret_cast<char*>(words_[middle])) == 0) {
found = true;
}
else if (left > reinterpret_cast<char*>(words_[middle]))
last = middle - 1;
else
first = middle + 1;
}
return found;
}
;
bool cleanupWord(char x[] ) {
bool lower = false;
int i = 0;
while (x[i]) {
char c = x[i];
putchar(tolower(c));
lower = true;
}
return lower;
}
int main()
{
char buffer[32];
Dictionary Websters("words.txt");
ifstream fin("gettysburg.txt");
cout << "\nSpell checking " << "gettysburg.text" << "\n\n";
while (fin >> buffer) {
if (cleanupWord(buffer) == true) {
if (!Websters.find(buffer)) {
cout << buffer << " not found in the Dictionary\n";
}
}
}
system("PAUSE");
}
当我运行该程序时,它在输出“拼写检查Gettysburg.txt”后停止,我不知道为什么。谢谢!
答案 0 :(得分:1)
此问题的最可能原因是文本文件尚未打开。使用is_open
添加支票以确保已将其打开。
在使用相对路径(不会完全回到文件系统根目录(并且是绝对路径)的任何路径)时,请注意要从您认为它所在的目录中运行程序。它并不总是与可执行文件相同。用于搜索有关此内容的搜索字词:工作目录。
由于其他原因,该程序无法运行:
void addWordToDictionary(char* word) { words_ += *word; };
没有在字典中添加单词。相反,它以words_
字母的数值前移*word
所指向的地址。这极具破坏性,因为它丢失了指向构造函数中为words_
分配的缓冲区的指针,从而使delete[] words_;
析构函数中的Dictionary
无效,并且可能致命。
相反,您想要(请注意,我有些想不到地使用了。。您真正想做的是使用std::vector
和std::string
,但我强烈怀疑这会破坏作业的标记)
Word
动态分配一个新的new
。words_
数组中的任意位置。与words_[numberOfWordsInDictionary_] = myNewWord;
numberOfWordsInDictionary_
增加1。请注意,分配给Word
的{{1}}必须全部在new
析构函数中释放。您将需要一个Dictionary
循环来帮助解决这个问题。
此外,我会移动
for
从 if (numberOfWordsInDictionary_ == capacity_)
{
resize();
}
到Dictionary
,以便在每次调用addWordToDictionary
时都具有适当的大小。
嗯。当我们讨论它时,让我们看一下addWordToDictionary
resize
这会增加对象的void resize() {
capacity_ = capacity_ * 2;
cout << "Size = " << capacity_ << endl;
};
,但不会为capacity_
分配更多的存储空间。这需要纠正。您必须:
words_
的值加倍。您已经有这个。capacity_
替换为words_
。new
中的所有Word
复制到较大的缓冲区。words_
当前指向的缓冲区words_
指向更大的新缓冲区。我没有仔细研究words_
,因为修复字典的阅读和存储所需的大屠杀很可能使find
无法使用,即使它目前可以使用。但是,find
的使用是一个警钟。在find函数中应该没有理由进行强制转换,更不用说其中最宽松的了。经验法则:当看到reinterpret_cast<char*>
时,您不知道它的用途是什么,请假设它隐藏了一个错误,并谨慎谨慎地对待它。
除了调查注释中提到的“三规则”外,还应研究Rule of Five。这将使您可以基于reinterpret_cast
制作更简单,可能更高效的字典,其中Word* words_
将直接指向words_
的数组,而不是指向{{1}的指针} s。