【问题标题】:Segmentation fault while implementing chaining in hash table after collisions occur发生冲突后在哈希表中实现链接时出现分段错误
【发布时间】:2018-06-03 06:26:23
【问题描述】:

我正在尝试实现链接(哈希表中的冲突解决技术)。我的程序适用于大多数测试用例。

这是我的程序(它很大,但我知道哪里出错了。所以如果你愿意,可以跳过这部分。):

#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)

程序为此测试用例提供SIGSEGV

输入要存储的元素

5

输入数组中的元素

21 32 565 784 445

输入要搜索的元素

565

温度 = 35383520

temp->data=445

温度 = 35383456

temp->数据=565

分段错误(核心转储)

调试后发现它在第 56 行抛出 seg fault,即:

if (key == temp->data)

这一行是写在这段代码sn-p中的:

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

正如您在上面的失败测试中看到的那样,while 循环执行了 3 次(它应该只执行两次,因为 temp 应该第三次指向 null)。在第三次执行时,它在if (key == temp-&gt;data) 行抛出段错误。

表示 temp 不是NULL,甚至没有data 字段。所以插入时可能会出现问题(即在插入newNode的下一个字段时可能不会NULL,但我正在妥善处理那件事。)如果插入时出现问题,那么我的代码应该其他测试用例也失败。但是对于上面指定的测试用例,代码只是失败了。

例如,代码通过了这个测试用例:

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

输入要存储的元素

7

输入数组中的元素

21 32 565 784 445 655 84

输入要搜索的元素

565

温度 = 8063248

temp->data=655

温度 = 8063216

temp->data=445

温度 = 8063152

temp->数据=565

找到 565 个

我只是想不通,为什么它没有通过提到的测试用例。

【问题讨论】:

  • 你应该使用 %p 而不是 %d 打印出指针
  • @ChrisTurner 是的,我应该(我只是想以十进制而不是十六进制查看内存,所以我使用了 %d),但现在没关系,因为我只是将 printf() 用于调试目的.
  • printf("\nTEMP = %d", temp); 你想在这里用%d 打印一个结构,为什么?
  • @Michi 我刚刚打印了 temp 以查看 temp 中实际存在的内容(如果它为 null,那么它应该自己给 SIGSEGV,但它没有给 SIGSEGV,SIGSEGV 在访问 data 后即将到来场地)。即使我删除 printf("\nTEMP = %d", temp); 问题仍然存在

标签: c algorithm hash segmentation-fault


【解决方案1】:

您的代码在许多地方的问题在于,您无法确保在索引到 hashTable 时保持在最初分配的范围内。

在您的示例中,数字 565 将生成 5 的 hashedValue。您只在 hashTable 中分配了 5 个元素,但它涵盖了 0 到 4 的范围。插入hashTable[5] 会进入未定义行为领域,您的代码会崩溃。输入 7 个数字时不会遇到同样的问题,因为所有 7 个数字都会生成介于 0 到 6 之间的hashedValues。

由于您的 hashFunction 只会返回 0 到 9 之间的数字,您可以声明一个新变量来跟踪 hashTable 的大小并在输入数字时扩展它,或者预先分配它以获得最大大小。

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

从长远来看,另一个选项会更有意义,因为如果您更改 hashFunction,它会适应。

【讨论】:

    【解决方案2】:

    你的问题在这里:你没有正确初始化哈希表。你写道:

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

    由于你的哈希表有 10 个桶,它应该是 i

    当 n == 5 时,hashTable[5] 没有初始化,有垃圾。当 545 被散列时,它会将垃圾作为下一个指针,而不是 NULL。

    【讨论】:

      猜你喜欢
      • 2016-08-13
      • 2014-03-28
      • 2018-05-09
      • 1970-01-01
      • 2018-11-05
      • 2020-09-30
      • 1970-01-01
      • 2022-07-21
      • 2021-01-19
      相关资源
      最近更新 更多