简体   繁体   中英

Segmentation fault while implementing chaining in hash table after collisions occur

I am trying to implement chaining (collision resolution technique in hash table). My program works fine for most of the test cases.

Here is my program (it's quite big, but I know where it is failing. So you can skip this part if you want.):

#include<stdio.h>
#include<stdlib.h>

struct LinkedListNode
{
    int data;
    struct LinkedListNode *next;
};

struct LinkedListNode* getNewNode()
{
    // I don't need to cast the malloc in c
    return malloc(sizeof(struct LinkedListNode));
}

struct LinkedListNode* insertAtBeginning(struct LinkedListNode** hashTable, int index, int data)
{
    struct LinkedListNode* newNode = getNewNode(); // the new node
    newNode->data = data;
    newNode->next = NULL; // for now I can put the next to be null

    // check if the block is containing null or not
    if (hashTable[index] == NULL)
    {
        // now just insert the new element at beginning
        hashTable[index] = newNode;
        return hashTable[index]; // returning the new address of the block
    }

    // if collisions occur
    struct LinkedListNode* blockListAddress = hashTable[index]; // the address pointing to first node of linked list
    newNode->next = blockListAddress; // storing the address of block in the next of the new linkedlist
    hashTable[index] = newNode; // changing the block address to the address of new node (as we have to insert in beginning)
    return hashTable[index];
}

struct LinkedListNode* searchMe(struct LinkedListNode** hashTable, int index, int key)
{
    struct LinkedListNode* res = NULL;
    struct LinkedListNode* temp = hashTable[index];

    if (temp == NULL)
        return NULL;

    // if we just have one element in the block then the while loop below won't get executed
    // because here condition is temp->next which will be null, thus here I have written if condition
    if (hashTable[index] != NULL && hashTable[index]->data == key)
    {
        return hashTable[index];
    }

    // if not null then traverse through linked list
    while (temp != NULL)
    {
        printf("\nTEMP = %d", temp);
        if (key == temp->data)
            res = temp;
        printf("\ntemp->data=%d\n", temp->data);
        temp = temp->next;
    }
    return res;
}

int hashFunction(int num)
{
    return num%10;
}

int main()
{
    int n;
    printf("\nEnter elements to be stored\n");
    scanf("%d", &n);

    // declaring the hashTable of size n (i.e. size of input elements), its gonna have pointers to LinkedListNode
    struct LinkedListNode** hashTable = malloc(n*sizeof(struct LinkedListNode*)); // I have given memory to the table, now I even need to give memory to the elements in the table
    int i;
    for (i = 0; i < n; ++i)
    {
        hashTable[i] = NULL;
    }

    int d;
    printf("\nEnter the elements in array\n");
    for (i = 0; i < n; ++i)
    {
        scanf("%d", &d);
        int hashedValue = hashFunction(d);
        hashTable[hashedValue] = insertAtBeginning(hashTable, hashedValue, d);
    }

    int key;
    printf("\nEnter the element you want to search for\n");
    scanf("%d", &key);
    int ind = hashFunction(key);
    struct LinkedListNode* res = searchMe(hashTable, ind, key);

    if (res == NULL)
    {
        printf("\nNot found\n");
    }
    else
    {
        printf("\n%d is found\n", res->data);
    }
}


// time complexity in worst case for searching = O(n),
// average case t.c = O(1+alpha), where alpha = n/m
// n <- number of elements in hashtable
// m <- size of hashtable
// so alpha is 1 in this case
// thus average t.c = theta(1)

The program gives SIGSEGV for this test case:

Enter elements to be stored

5

Enter the elements in array

21 32 565 784 445

Enter the element you want to search for

565

TEMP = 35383520

temp->data=445

TEMP = 35383456

temp->data=565

Segmentation fault (core dumped)

After debugging I found that it's throwing seg fault at line number 56, ie:

if (key == temp->data)

This line is written in this code snippet:

while (temp != NULL)
{
    printf("\nTEMP = %d", temp);
    if (key == temp->data)
        res = temp;
    printf("\ntemp->data=%d\n", temp->data);
    temp = temp->next;
}

As you can see in the failing test above that, the while loop is executing 3 times (it was supposed to be executed only twice, because the temp should point to null for the third time). And while it is executing 3rd time, it's throwing segfault at the line if (key == temp->data) .

It means that temp is not NULL , and it even doesn't has data field. So there might be the problem in the insertion (ie while inserting the next field of the newNode might not be made NULL , but I am properly taking care of that thing.) If there would be the problem in insertion then my code should fail of other test cases too. But the code is just failing for the specified test case above.

For example, the code passes this test case:

[aupadhyay@localhost c]$ ./a.out

Enter elements to be stored

7

Enter the elements in array

21 32 565 784 445 655 84

Enter the element you want to search for

565

TEMP = 8063248

temp->data=655

TEMP = 8063216

temp->data=445

TEMP = 8063152

temp->data=565

565 is found

I am just unable to figure it out, why does it fail the mentioned test case.

The problem with your code in many places, is that you don't ensure that when indexing into hashTable that you remain within the bounds that you allocate initially.

In your example, the number 565 would generate a hashedValue of 5. You've only allocated 5 elements in hashTable which covers you for the range of 0 to 4 though. Inserting into hashTable[5] enters the realm of undefined behaviour and your code crashes. You don't get the same problem when you enter in 7 numbers because all 7 numbers generate hashedValue s that are within the range 0 to 6.

Since your hashFunction will only return numbers between 0 and 9, you could either declare a new variable that tracks the size of hashTable and expands it as numbers are entered or alternatively pre-allocate it for the maximum size.

struct LinkedListNode** hashTable = malloc(10*sizeof(struct LinkedListNode*)); // I
int i;
for (i = 0; i < 10; ++i)
{
    hashTable[i] = NULL;
}

In the long term the other option would make more sense as it will adapt if you ever change hashFunction .

You problem is here: you do not correctly initialize the hash table. You wrote:

int i;
for (i = 0; i < n; ++i)
{
    hashTable[i] = NULL;
}

Since your hashtable has 10 buckets, it should be i < 10.

When n == 5, hashTable[5] is not initialzed and has garbage. When 545 gets hashed, it gets that garbage as it's next pointer, not NULL.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM