0

Alright, so I have spent days with with load, and just recently implemented check. I've read upon stuff, rewatched videos, all the good stuff.

I'm trying to do pset5 (misspellings) with Tries. I think I got the logic right, but something seems off. I got 2 problems (or probably more) that I can't seem to figure out:

1. When I run speller.c with the Austin Powers text, I get all words containing apostrophes as misspelled back and nothing else.

This means:

a) for some odd reason my code fails to identify apostrophes either in the load() of the check() function b) non-correct words are identified as correct (I'm guessing something might be wrong with bool is_word)

2. I realized I'm not sure about return in general. In my check() function I thought the function returns the (bool) value as soon as it hits a return statement - which should always happen in my last else if block. But it seems that is not the case. If I change the last return true to return false, then it lists all words, meaning everything was false.

This means:

a) All this time I was wrong about return, and it doesn't necessarily end a function b) something is really off with my code and for some reason it reaches the last return statement

Now... I'm not sure how much code I can show without breaching academic honesty, but I feel almost the whole thing is needed to identify the flaw(s). With that said, I'll try to post as little code as possible, if you guys think it's too much, I'll gladly remove it.

With that said, here's load():

bool load(const char* dictionary)
{

// creating root node and checking if it's NULL
root = malloc(sizeof(node));
node* current = root;

if (root == NULL)
{
printf("Could not create root node\n");
return false;
}

// setting root pointers to NULL
for (int i = 0; i < 27; i++)
{
    root -> path[i] = NULL;
}

// opening dictionary for reading and checking if it is NULL
FILE* dic = fopen(dictionary, "r");
if (dic == NULL)
{
    printf("Could not open dictionary\n");
    return false;
}

// setting up variables for the iteration
//int count = 0;
int j = 0;
char buffer[LENGTH+1];

// iterate throught the dictionary, word by word
while (fgets(buffer, LENGTH + 1, dic) != NULL)
{

    // resetting the current pointer at each word
    current = root;
    current -> is_word = false;

    //iterate through each word, letter by letter
    for (char* i = buffer; *i != '\n'; i++)
    {

        // creating a variable to store letters in
        int templetter = i[j];

        if (templetter >= 'a' && templetter <= 'z')
        {

            // checking if the node's path field is empty
            if (current -> path[templetter - 'a'] == NULL)
            {
                node* newnode = malloc(sizeof(node));

                if (newnode == NULL)
                {
                printf("Could not create new node\n");
                    return false;
                }

                // setting newnode's path field array to NULL, and is_word to false
                newnode -> is_word = false;
                for (int i = 0; i < 27; i++)
                {
                    newnode -> path[i] = NULL;
                }

                // setting current pointer to point to newnode    
                current -> path[templetter - 'a'] = newnode;
            }
            else
            {
                // set the current pointer to the next node if it is already 'open'
                current = current -> path[templetter - 'a'];
            }
        }

        // same as above but for apostrophe
        else if (templetter == '\'')
        {
            // checking if the node's path field is empty
            if (current -> path[26] == NULL)
            {
                node* newnode = malloc(sizeof(node));

                if (newnode == NULL)
                {
                printf("Could not create new node\n");
                    return false;
                }

                // setting newnode's path field array to NULL and is word to false
                newnode -> is_word = false;
                for (int i = 0; i < 27; i++)
                {
                    newnode -> path[i] = NULL;
                }

                current -> path[26] = newnode;
            }
            else
            {
                current = current -> path[26];
            }
        }
        else if (templetter == '\0')
        {
            current -> is_word = true;
        }
    j++;
    }
    j = 0;        
}
return true;
}

I know, doing the same code twice is not the prettiest of solutions...

and here is check():

bool check(const char* word)
{   
// declaring a variable to hold the current letter
int modletter;

// setting up a pointer for traversal
node* checker = root;

// iterating through each string in word
for (int z = 0; z < strlen(word); z++)
{
    // if uppercase
    if (word[z] >= 'A' && word[z] <= 'Z')
    {
        modletter = word[z] - 'A';
    }

    // if lowercase
    else if (word[z] >= 'a' && word[z] <= 'z')
    {
        modletter = word[z] - 'a';
    }

    // if apostrophe
    else if (word[z] == '\'')
    {
        modletter = 26;
    }

    // move pointer if path exists
    if (checker -> path[modletter] != NULL)
    {
        checker -> path[modletter] = checker;      
    }

    // check to see if at the current pointer there is a word ending
    else if (checker -> path[modletter] == NULL)
        {
            if (checker -> is_word == true)
                return true;
            else
                return false;
        }
}
return true;
}

So... any hints from anyone? I've thought it through tons of times, and it seems correct to me. But obviously, it's not.

1 Answer 1

1

There are several problems. The most significant is this:

for (char* i = buffer; *i != '\n'; i++)
{
    // creating a variable to store letters in
    int templetter = i[j];

This code is supposed to get the next letter and store it in templetter. However, it is skipping letters. Consider this: the for loop increments the i pointer. That means that it will move from one char to the next. The next line says " copy the letter at i[j] into templetter ", but on each pass, j is incremented. In short, it is reading i[0], then i[2], then i[4], i[6], etc., skipping every other letter.

Next, the code will only set is_word=true when \0 is encountered. That never happens. Each word has \n after the last letter and before the end of string marker. Unfortunately, the for loop terminates when \n is detected and the code moves on to the next word. The result is that nothing is ever marked as a word.

There's also an issue with the last word in the dictionary, which I haven't quite sorted out. I'll leave that in your hands.

There are more issues, but this is enough to get you started on getting load() working correctly. To be honest, I didn't get load working, so I haven't looked at check. But then, I can't take away all of your fun! :-D

If this answers your question, please click on the check mark to accept. Let's keep up on forum maintenance. ;-)

5
  • Thank you once again @Cliff B! I hope you don't mind if I leave this thread a bit open still, until I implement the changes you suggested, and try to figure out what you implied. These pset truly are fun, and the more challenging they are, the more satisfaction they bring! \n being part of the string is news to me. I thought first comes the \0, and then \n indicates, that "by the way, the line is over too".
    – Bubi
    Commented Feb 18, 2016 at 21:40
  • Alright, making progress. Fixed the loop,fixed the end of strings thing (now it should correctly read up until \n) and noticed a major bug with my pointers. Now load() and check() are returning misspelled words correctly, however compared to the staff's implementation, it seems they output more misspelled words than I do. Gonna look into that next!
    – Bubi
    Commented Feb 19, 2016 at 13:13
  • Aaaaand it works! Compared to the staff's implementation at least, I got all words. Wow... messed around hours with the return true and return false statements. I can hardly believe it works. To be honest, I still don't understand why one of the return falses was needed at the end of check(), but hey! It works. Once again, many thanks Cliff! Your advices were just enough to get me on the right path!
    – Bubi
    Commented Feb 19, 2016 at 18:37
  • Glad you got it. Re: the final return false - in general, there needs to be one final, unconditional return false in a function that returns a bool. It's there as a catchall just in case the input data can produce a state where the code can run all the way through and not hit a return (whether true or false). It's almost always a return FALSE because you don't want to return true unless the test conditions really are met.
    – Cliff B
    Commented Feb 19, 2016 at 19:05
  • I see. Well, you learn something new everyday :)
    – Bubi
    Commented Feb 19, 2016 at 21:18

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .