Search code examples
c++data-structureshashhashmaphashtable

Hash table prints out default values but when items are added results into Address Boundary Error


Trying to create a Hash Table with name as key and it's value as the drink, when printTable() is invoked without adding items (i.e. commenting out the following code snippet) it prints out the added image without any address boundary error :

h.addItem("Paul", "Locha");
h.addItem("Kim", "Iced Mocha");
h.addItem("Emma", "Strawberry Smoothy");
h.addItem("Annie", "Hot Chocolate");
h.addItem("Sarah", "Passion Tea");
h.addItem("Pepper", "Caramel Mocha");
h.addItem("Mike", "Chai Tea");
h.addItem("Steve", "Apple Cider");
h.addItem("Bill", "Root Bear");
h.addItem("Marie", "Skinny Latte");

Image of output with given default values

Image of output with given default values

But when items are added either by parsing csv or directly calling the class member function of addItem(), the program renders an error like so :

➜  Hash Table ./hashTableWithStruct.o
fish: Job 1, './hashTableWithStruct.o' terminated by signal SIGSEGV (Address boundary error) 

The erroneous code is herewith :

hashTableWithStruct.cpp

#include <iostream>
#include <string>
#include <fstream>
using namespace std;

class Hash
{
private:
    static const int tableSize = 10;

    struct item
    {
        string name;
        string drink;
        item *next;
    };

    item *hashTable[tableSize];

public:
    Hash()
    {
        for (int i = 0; i < tableSize; i++)
        {
            hashTable[i] = new item;
            hashTable[i]->name = "empty";
            hashTable[i]->drink = "empty";
            hashTable[i]->next = NULL;
        }
    }

    int hashFunct(string key)
    {
        int hashed = 0;
        for (int i = 0; key[i] != '\0'; i++)
        {
            hashed += (int)key[i];
        }
        return (hashed % tableSize); //returns the BUCKET value
    }

    void addItem(string name, string drink)
    {
        int BUCKET = hashFunct(name);
        //if the value at BUCKET hasn't been written yet,
        //override the default empty ones
        if (hashTable[BUCKET]->name == "empty")
        {
            hashTable[BUCKET]->name = name;
            hashTable[BUCKET]->drink = drink;
        }
        //otherwise, make a linked list starting from BUCKET
        else
        {
            item *ptr = hashTable[BUCKET];

            item *n = new item;
            n->name = name;
            n->drink = drink;
            n->next = NULL;

            //the linked list might contain many nodes,
            //hence travel to last node and reassign the last node to be this new item
            while (ptr != NULL)
                ptr = ptr->next;
            ptr->next = n;
        }
        return;
    }

    int numOfItemsInBucket(int BUCKET)
    {
        int count = 0;
        if (hashTable[BUCKET]->name == "empty")
            return count;
        else
        {
            count++;
            item *ptr = hashTable[BUCKET];
            while (ptr->next != NULL)
            {
                count++;
                ptr = ptr->next;
            }
        }
        return count;
    }

    void printTable()
    {
        int num; //holds number of elements(items) in each bucket
        for (int i = 0; i < tableSize; i++)
        {
            num = numOfItemsInBucket(i);
            cout << "-----------------------------\n"
                 << "Table[" << i << "]" << endl
                 << hashTable[i]->name << endl
                 << hashTable[i]->drink << endl
                 << "# of items in bucket " << i << " : " << num << endl;
            cout << "-----------------------------\n";
        }
    }
};

int main(int argc, char const *argv[])
{
    Hash h;
    /* string filename = "datasetForHashTable.csv";
    ifstream myCSV(filename.c_str());
    if (!myCSV.is_open())
    {
        cout<<"Failed to open file"<<endl;
        return 0;
    }
    string name, drink;
    while (myCSV.peek()!=EOF)
    {     
        getline(myCSV, name, ',');
        getline(myCSV, drink, '\n');
        h.addItem(name, drink);
    }
    myCSV.close(); */

    h.addItem("Paul", "Locha");
    h.addItem("Kim", "Iced Mocha");
    h.addItem("Emma", "Strawberry Smoothy");
    h.addItem("Annie", "Hot Chocolate");
    h.addItem("Sarah", "Passion Tea");
    h.addItem("Pepper", "Caramel Mocha");
    h.addItem("Mike", "Chai Tea");
    h.addItem("Steve", "Apple Cider");
    h.addItem("Bill", "Root Bear");
    h.addItem("Marie", "Skinny Latte"); 

    h.printTable();
    return 0;
}

Basically, can't understand why the table won't print with name and drinks, since it works just fine when table is printed without it. Please help, trying to figure this out since 2 days.


Solution

  • After this while loop

            while (ptr != NULL)
                ptr = ptr->next;
    

    the pointer ptr is equal to nullptr. So the next statement

            ptr->next = n;
    

    invokes undefined behavior due to dereferencing a null pointer.

    It seems you mean

            while (ptr->next != NULL)
                ptr = ptr->next;
    
            ptr->next = n;