Search code examples
clinked-listhashtable

Function to insert node in linked list


I'm reading in words from a dictionary and then adding them to linked lists in a hash table. This works fine when I try inserting the nodes for each word within the while loop.

// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
    FILE *dict = fopen(dictionary, "r");
    if (dict == NULL)
    {
        return false;
    }

    // Set all next pointers to NULL in hash table
    for (int i = 0; i < N; i++)
    {
        table[i] = NULL;
    }

    char word[LENGTH + 1];
    while(fscanf(dict, "%s", word) != EOF)
    {
        // Get key from hash function
        unsigned int key = hash(word);

        node *pNode = getNode(word);

        if (table[key] != NULL)
        {
            pNode->next = table[key];
        }

        table[key] = pNode;

        words++;
    }
    fclose(dict);
    return true;
}

I've tried refactoring this to a function insertNode with the exact same code but it doesn't work and the nodes seem to get lost and cause a memory leak. I assume it has something to do with how the arguments are passed into the function but as head is a pointer I would've thought it would work fine.

void insertNode(node *head, const char *key)
{
    // Create node
    node *pNode = getNode(key);

    // Insert node into linked list
    if (head != NULL)
    {
         // Make new node point to first item in linked list (a.k.a head)
         pNode->next = head;

    }
    // Now point head to new node
    head = pNode;
}

so the while loop within load would just call the function (which is defined before)

char word[LENGTH + 1];
while(fscanf(dict, "%s", word) != EOF)
{
    // Get key from hash function
    unsigned int key = hash(word);

    // Add value to Hash table with head of linked list
    insertNode(table[key], word);

    words++;
}

Solution

  • As the 'head' variable is a pointer, you can just pass the value of 'head' by this pointer not the pointer itself, and in this case you try to override the local pointer inside the function.

    Well look at this example to assign/change value to the pointer:

    #include <stdio.h>
    
    class A {
    public:
        int x;
    };
    
    // pass pointer by copy
    void initialize(A* obj) {
    
        obj = new A(); // obj not null here
        obj->x = 2;
    
        printf("x: %d\n", obj->x);
    }
    
    int main() {
    
        A *a = nullptr;
    
        initialize(a);
    
        // a is still null here (pointer passed by copy)
    
        printf("x: %d\n", a->x); // seg fault here, read on null
    
        return 0;
    }
    

    The following code as you can see is incorrect. To fix this example you have to change the function prototype, and pass the pointer by pointer so it should lool like this:

    #include <stdio.h>
    
    class A {
    public:
        int x;
    };
    
    // pass pointer by pointer
    void initialize(A** obj) {
    
        *obj = new A(); // obj not null here
        (*obj)->x = 2;
    
        printf("x: %d\n", (*obj)->x);
    }
    
    int main() {
    
        A *a = nullptr;
    
        initialize(&a); // get the pointer address
    
        // a is valid object here
    
        printf("x: %d\n", a->x); // no error, x == 2
    
        return 0;
    }
    

    So in your case it should be:

    insertNode(&table[key], word);
    

    and

    void insertNode(node **head, const char *key)
    {
        // Create node
        node *pNode = getNode(key);
    
        // Insert node into linked list
        if (*head != NULL)
        {
             // Make new node point to first item in linked list (a.k.a head)
             pNode->next = *head;
    
        }
        // Now point head to new node
        *head = pNode;
    }