Spell-checking application in C++ This is my current coursework for university where I am to write a spell checking application and compile using C++11.

I have a dictionary file that is read into the program automatically and stored into a binary search tree in order. The user provides a text file that they would like to check which is split into tokens and stored in a string vector.

The program then loops through the string vector and checks if that word exists in the BST. If the word is not in the BST, it will print the word to the console as incorrectly spelled.

#include &lt;iostream&gt;
#include &lt;sstream&gt;
#include &lt;fstream&gt;
#include &lt;vector&gt;
#include &lt;cstring&gt;
#include "bst.h"

using namespace std;

string read_file(string &amp;filename)
{
    ifstream file(filename);
    // If there is a file
    if (file)
    {
        string data;
        // Find total number of bytes of file
        file.seekg(0, file.end);
        data.resize(file.tellg());
        file.seekg(0, file.beg);
        // Read text into data string
        file.read(&amp;data[0], data.size());
        // Close the file
        file.close();
        // Return the string
        return data;
    }
    else return string("");
}

void split_words(vector&lt;string&gt; &amp;words, string &amp;data)
{
    char *token, *delim = " .,?!:;/\"\'\n\t";
    // Set token to first word
    token = strtok(&amp;data[0], delim);
    // Split rest of words
    while (token != nullptr)
    {
        // Convert each word from dictionary to lower case
        for (int i = 0; i &lt; strlen(token); ++i)
        {
            char word = tolower(token[i]);
            token[i] = word;
        }
        // Push word to end of vector
        words.push_back(token);
        // Get the next word
        token = strtok(nullptr, delim);
    }
    // Free the memory
    token = nullptr;
    delim = nullptr;
    delete token;
    delete delim;
}

int main(int argc, char **argv)
{
    string file_to_check, file_data, word_dictionary = "dictionary.txt";
    int spell_count = 0;

    BinarySearchTree *tree = new BinarySearchTree();
    vector&lt;string&gt; words;

    // Loop through arguments
    for (int i = 0; i &lt; argc; ++i)
    {
        // Set file name if provided as argument
        if (string(argv[i]) == "-i" &amp;&amp; argv[i+1] != nullptr)
            file_to_check = argv[i+1];
    }

    // If there was no file name as argument, prompt user
    if (file_to_check.empty())
    {
        cout &lt;&lt; "File name: ";
        getline(cin, file_to_check);
        cout &lt;&lt; endl;
    }

    // If file name is not empty, run spell checking methods
    if (!file_to_check.empty())
    {
        // Read words from dictionary.txt into file_data string
        file_data = read_file(word_dictionary);
        // Split the words and store into vector
        split_words(words, file_data);
        // Insert words into Binary Search Tree
        for (int i = 0; i &lt; words.size(); ++i)
            stringstream(words[i]) &gt;&gt; *tree;

        // Store the data read from specified file
        file_data = read_file(file_to_check);
        // Split sentences and store each word in words vector
        split_words(words, file_data);
        cout &lt;&lt; endl;

        // Loop through words vector and check if it exists in dictionary
        for (int i = 0; i &lt; words.size(); ++i)
        {
            // Print out non-occurring words
            if (!tree-&gt;exists(words[i]))
            {
                spell_count++;
                cout &lt;&lt; words[i] &lt;&lt; endl;
            }
        }
        cout &lt;&lt; endl;

        // Print the total number of spelling mistakes
        cout &lt;&lt; spell_count &lt;&lt; " spelling mistakes" &lt;&lt; endl;
    } 
    else
    {
        // If still no file specified, print message and exit
        cout &lt;&lt; "No file specified!" &lt;&lt; endl;
        return 0;
    }

    // Free the memory
    delete tree;

    return 0;
}
using namespace std; Never do this
Prefer using \n over std::endl as the latter flushes the buffer which is rarely needed and can be detrimental to performance.
const your arguments whenever possible. More about const correctness
* and &amp; are considered to be part of the type in C++ so prefer writing int&amp; foo instead of int &amp;foo. Likewise for *.
Never omit optional braces as doing so will lead to bugs eventually.
Reaching the end of main will automatically return 0 so you can remove the trailing return 0
Don't initialize more than one variable per line.
I like that you use the prefix operator. Your naming is pretty good too so why are you doing this?

// Close the file
file.close();


or this

// Loop through arguments
for (int i = 0; i &lt; argc; ++i)


Your comments are completely superfluous and can all be removed.
What is this?

// Free the memory
token = nullptr;
delim = nullptr;
delete token;
delete delim;



delete is only used after a matching new. It feels like you misunderstood something in regard to memory managment. Read up on this again.
new
delete
memory managment


BinarySearchTree *tree = new BinarySearchTree();


I don't know how this is implemented but a line like that looks like something from Java. Do you really need to put this on the heap?


Personally I think the word splitting could be done rather elegantly in regex. However many people are quite opposed to using regex. I've also read that in the past regex performance in C++ was rather poor but it might be worth measuring to see if it's within acceptable limits for your use-case.  


Regex example:

std::regex rx{R"(([^ .,?!:;/\"\'\n\t]+))"};
auto data_begin = std::sregex_iterator(data.begin(), data.end(), rx);
auto data_end = std::sregex_iterator();
for (std::sregex_iterator it = data_begin; it != data_end; ++it) {
    // do something with words here
}