具有两个类的C ++拼写检查程序;字典和单词

时间:2019-01-15 22:19:57

标签: c++

这是代码的规范: 您将使用下面定义的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”后停止,我不知道为什么。谢谢!

1 个答案:

答案 0 :(得分:1)

此问题的最可能原因是文本文件尚未打开。使用is_open添加支票以确保已将其打开。

在使用相对路径(不会完全回到文件系统根目录(并且是绝对路径)的任何路径)时,请注意要从您认为它所在的目录中运行程序。它并不总是与可执行文件相同。用于搜索有关此内容的搜索字词:工作目录。

由于其他原因,该程序无法运行:

void addWordToDictionary(char* word) { words_ += *word; };

没有在字典中添加单词。相反,它以words_字母的数值前移*word所指向的地址。这极具破坏性,因为它丢失了指向构造函数中为words_分配的缓冲区的指针,从而使delete[] words_;析构函数中的Dictionary无效,并且可能致命。

相反,您想要(请注意,我有些想不到地使用了。您真正想做的是使用std::vectorstd::string,但我强烈怀疑这会破坏作业的标记)

  1. Word动态分配一个新的new
  2. 将此单词放在words_数组中的任意位置。与words_[numberOfWordsInDictionary_] = myNewWord;
  3. 相似
  4. 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_分配更多的存储空间。这需要纠正。您必须:

  1. words_的值加倍。您已经有这个。
  2. 分配更大的缓冲区以将capacity_替换为words_
  3. new中的所有Word复制到较大的缓冲区。
  4. 释放words_当前指向的缓冲区
  5. words_指向更大的新缓冲区。

附录

我没有仔细研究words_,因为修复字典的阅读和存储所需的大屠杀很可能使find无法使用,即使它目前可以使用。但是,find的使用是一个警钟。在find函数中应该没有理由进行强制转换,更不用说其中最宽松的了。经验法则:当看到reinterpret_cast<char*>时,您不知道它的用途是什么,请假设它隐藏了一个错误,并谨慎谨慎地对待它。

除了调查注释中提到的“三规则”外,还应研究Rule of Five。这将使您可以基于reinterpret_cast制作更简单,可能更高效的字典,其中Word* words_将直接指向words_的数组,而不是指向{{1}的指针} s。