0

The compiler reported errors on the first few lines where I defined struct node and allocated memory and on the parameter 'dictionary' in size(). I don't why they are wrong. Someone please help me out. Thank you!

#include <stdbool.h>
#include <stdlib.h>
#include <ctype.h>    
#include <string.h>
#include <stdio.h>


#include "dictionary.h"

// Define a struct node to store words
typedef struct node
{
    bool is_word;
    struct node* children[27] = {};
}
node;

// Set the root of tries
node* root = malloc(sizeof(node));

/**
 * Returns true if word is in dictionary else false.
 */
bool check(const char* word)
{
    // TODO
    node* current_node = root;
    for (int i = 0; word[i] != '\0'; i++)
    {
        // Calculate the index of the pointer of the corresponding trie. 
        int index = (isalpha(word[i])) ? (tolower(word[i]) - 'a'): 26; 
        // If the letter is in the loaded dictionary
        if (current_node -> children[index] != NULL)
        {
            // If the letter is the end of a word.
            if (current_node -> is_word == true)
            {
                return true;
            }
            else
            {
                current_node = current_node -> children[index];
            }
        }
        // If the letter is not in the loaded dictionary
        else
        {
            return false;
        }
    }

    return false;
}

/**
 * Loads dictionary into memory.  Returns true if successful else false.
 */

int word_counter = 0;
bool load(const char* dictionary)
{
    // Read words from dictionary and store them in the tries
        // Read the first letter
        // Store it in the relevant children array (node -> children[x])
        // Read the next letter
        // Store it in the relevant children array (node -> children[x] -> children[x])
        // If a space is read, set is_word true. And contine the loop.  

    // Open the dictionary
    FILE* infile = fopen(dictionary, "r");
    if (infile == NULL)
    {
        printf("Could not open %s.\n", dictionary);
        return false;
    }

    if (root == NULL)
    {
        printf("Memory allocation failed!");
        return false;// Or return 1???
    }

    node* current_node = root;
    for (int c = fgetc(infile); c != EOF; c = fgetc(infile))
    {
        if (c != '\n') 
        {
            // Calculate the index of the children array if c is a letter or an apostrophe.
            int index = (isalpha(c)) ? (c - 'a'): 26;  
            // If children[index] is NULL, add another node to it to suggest that the word hasn't ended yet.
            if (current_node -> children[index] == NULL)
            {
                current_node -> children[index] = malloc(sizeof(node));
                if (current_node -> children[index] == NULL)
                {
                    printf("Memory allocation failed!");
                    return false;// Or return 1???
                }
                current_node = current_node -> children[index];    
            }
            else
            {
                current_node = current_node -> children[index];
                word_counter ++;
            }

        }
        // If c is a '\n', mark the node as the end of the word.
        else
        {
            current_node -> is_word = true;
        }
    }

    fclose(infile);
    return true;
}

/**
 * Returns number of words in dictionary if loaded else 0 if not yet loaded.
 */
unsigned int size(void)
{
    // TODO
    bool loaded = load(dictionary);// E???
    if (loaded)
    {
        return word_counter;
    }
    else
    {
        return 0;
    }
}

/**
 * Unloads dictionary from memory.  Returns true if successful else false.
 */
void free_node(node* cursor);
bool unload(void)
{
    // TODO
    //node* current_node = root;
    for (int i = 0; i < 27; i++)
    {
        if (root -> children[i] != NULL)
        {
            free_node(root -> children[i]);
        }

    }

    free(root);
    return true;
}

void free_node(node* cursor)
{
    for (int i = 0; i < 27; i++)
    {
        // If the child pointer do not point to Null, 
        // it suggests that the pointer points to another node.
        // So dive into the child node.
        if (cursor -> children[i] != NULL)
        {
            cursor = cursor -> children[i];
            // and return the for loop
            return free_node(cursor);
        }
    }
    // Continue the for loop
    // If reach the end of the loop, it suggests the pointer array all point to null.
    // Now you can free the current node.    
    free(cursor);
}
1

struct node* children[27] = {}; This is an error because this is part of a typedef. You can't assign values or initialize in a typedef. A typedef is not a variable, so it cannot be initialized. Once you create an actual var of that type, the var can then be initialized. Any initializations that are more than a constant, i.e., a calculation or allocation of memory, must be done inside of main() or a function.

node* root = malloc(sizeof(node)); root is declared as a global variable. This has a couple of impacts. Globals must be declared outside of main or any function in order to be globals. BUT, globals cannot be initialized with anything that requires a calculation or allocation that must be done at run time, unless it is done inside of a function or in main. They can only be initialized at declaration with constants that can be hardcoded at compile time, such as int x = 0; A malloc call can not be done at compile time, only at run time.

As for the sizeof(), it will work fine at run time. Moving the typedef to the .h file will have no effect. The problem wasn't the sizeof() call so much as it was both the malloc and sizeof calls being runtime calls.

The error of undeclared identifier 'dictionary' is because dictionary is not defined inside of size(). dictionary is only in scope inside of load(), as it is defined in the load() function declaration.

Also, when you try to call load() from size(), you will be executing the entire load function a second time. It will be called from main the first time. There is no need to check whether load executed. The main() code already handles it.

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

3
  • Thank you Cliff for your crystal clear explanation and your generous help! :))) – Kevin King Sep 21 '16 at 2:05
  • So thesize() function seems redundant. Can I leave it empty and let load() handle the size of the dictionary? – Kevin King Sep 21 '16 at 2:16
  • No. size() will be called to return the number of words. The good news is that most of the work is done in load. Your challenge is to figure out how to take advantage of it in size. I'll say that it's really simple, but I can't take all the fun away from you. ;-) – Cliff B Sep 21 '16 at 2:19
0

To fix the first error, your children node should be defined as node* children[27];. The second error could be fixed by moving the struct definition to dictionary.h, that way you can run sizeof() on it.

1
  • I want to set the children pointers point to NULL. Why setting them in 'typedef' won't work? And what is wrong with 'node* root = malloc(sizeof(node)); '? Thank you! – Kevin King Sep 21 '16 at 0:55

You must log in to answer this question.

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