哈希 table 没有 return 通过它的索引正确值

Hash table didn't return correct value by it's Index

我有这个 csv 文件包含联系人:

NAME, NUMBER, ADDRESS, EMAIL
Kevin Mahendra, +62 812-XXXX-XXXX, Jln.Anggrek Merah 3, kevinitsnovember@gmail.com
Adwi Lanang, +62 821-XXXX-XXXX, Jln.Ruhui Rahayu, adwilanang@gmail.com
Wasis Sirutama, +62 813-XXXX-XXXX, Jln.Pramuka 6 25, wasisnaruto@gmail.com
Alief Dean, +62 811-XXXX-XXXX, Jln.Padat Karya, aliefdean@gmail.com
Baharudin Nuri, +62 813-XXXX-XXXX, Jln.Ruhui Rahayu 1, baharudin008@yahoo.com
Yonggi Wijaya, +62 853-XXXX-XXXX, Jln.PM Noor Pondok S, yonggiwijaya@gmail.com
Artha Yoga, +62 822-XXXX-XXXX, Jln.A.Yani Gg.1, arthayoga97@gmail.com
Rusydi Nashier, +62 858-XXXX-XXXX, Jln.Perjuangan No.90, rusydinashier@gmail.com
Andre Pieters, +62 822-XXXX-XXXX, Jln.Villa Tamara No.1, azzahz@gmail.com
Paco Corleone, +62 816-XXXX-XXXX, Jln.Anggrek Merah 3, pacocorleone@gmail.com

这是我的 C 代码:

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

// Number of buckets for TABLE
#define N 26

#define MAX 50

typedef struct Contact
{
    char name[MAX];
    char number[MAX];
    char address[MAX];
    char email[MAX];
    struct Contact* next;
} 
Contact;

void searching_contact(FILE *file);
void load_hash_table(FILE **file);
unsigned int hash(const char *name);

// Hash table
Contact *table[N];

int main(void)
{  
    // OPEN CSV FILE AS append and read mode
    FILE *file = fopen("contacts.csv", "r");
    if (file == NULL)
    {
        printf("Error open file!\n");
        return 1;
    }

    searching_contact(file);

    fclose(file);
    return 0;
}    

void searching_contact(FILE *file)
{

    char name[MAX];

    printf("Search Name: ");
    scanf("%[^\n]%*c", name);
    fflush(stdin);

    // Load csv file into hash table first    
    load_hash_table(&file);

    // Get index number by calling hash function
    int hashIndex = hash(name);
    printf("\n\nIndex number we get from searching: %i\n", hashIndex);
    
    // Point to table that may contain the person
    Contact *cursor = table[hashIndex];
    
    // This will always print the last person
    printf("The name on the table: %s\n", cursor->name);

    // Keep traversing linked list in table
    while (cursor != NULL)
    {
        // If the person found, print the contact information
        if (strcmp(name, cursor->name) == 0)
        {
            printf("%s %s %s %s", cursor->name, cursor->number, cursor->address, cursor->email);
        }
        else
        {
            // If not the person, but in the same table, go to the next linked list
            cursor = cursor->next;
        }
    }
    printf("Not found!\n");
}

// FUNCTION TO LOAD CSV FILE INTO HASH TABLE
void load_hash_table(FILE **file)
{
    Contact *new = malloc(sizeof(Contact));
    if (new == NULL)
        exit(1);

    /*
        "%[^,], "
        Empty space or space after above sign will remove spaces or newline (\n) on each string
        Just because, when we try to use hash function, the spaces or newline will also include
        And we want to remove them so when user searching by name it will produce same hash index
    */
    while(fscanf(*file, "%[^,], %[^,], %[^,], %[^\n] ", new->name, new->number, new->address, new->email) == 4)
    {   
        // Skip header from CSV file   
        if (strcmp("NAME", new->name) == 0)
            continue;    
    
        // Get index number from hash function with People name as input
        int index = hash(new->name);

        // Try to print name and it's index in csv file for debugging
        printf("%s\n", new->name);
        printf("%i\n", index);
        
        /* 
            Create linked list point to WHAT inside Table[index]
            For very first struct, it points to NULL, then store it in Table
            Next struct, with the same Index number, it will point the first one
        */   
        new->next = table[index];
        table[index] = new;

        // Malloc for next fscanf
        Contact *new = malloc(sizeof(Contact));
        if (new == NULL)
            exit(1);
    }
}

// Hash function that will return index number from Table
unsigned int hash(const char *name)
{
    // TODO
    unsigned long hash = 5381;
    int c;

    while ((c = toupper(*name++)))
    {
        hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
    }
    return hash % N;
}

所以,我正在尝试制作一个程序,用户可以在其中按姓名搜索联系人。如您所见,我还想使用 散列 table/hash 函数 进行练习。所以在搜索之前,它会将所有 csv 文件加载到哈希 table 中(参见 load_hash_table())。但是最后,即使用户已经输入正确的名字,它也总是找不到人。

我尝试仅使用 printf 进行调试。

首先,在 load_hash_table() 函数中,我打印每个名称及其索引。它工作正常。它打印 csv 文件中的所有名称,并更正由 hash 函数生成的索引。

其次,问题来了。当我尝试在 searching() 函数中打印时。它产生了正确且相同的 index 数字。但是当我打印名字时,它总是在 csv 文件上打印最后一个人,即 Paco Corleone。无论我们在 Table[] 中输入什么索引号,它总是打印最后一个人的名字。

我不明白。当 load_hash_table() 函数内的 while 循环 结束时,散列 table 似乎丢失了之前加载的所有数据。当您 运行 我提供的代码时,您可能会发现问题。请帮助我,我是C语言的新手,谢谢!

几个问题:

  1. 主要问题是有两条Contact *new = malloc(sizeof(Contact));行。一个在环内,一个在环外。它们是两个 不同的 变量。 while 循环条件使用循环外的条件。因此 fscanf 正在为每个循环写入相同的内存。解决该问题的一种方法是使第二个实例仅 new = malloc(sizeof(Contact));。请注意,由于最后分配的节点丢失,此循环存在内存泄漏 - 留给您作为练习来修复。

  2. searching_contact 有一个无限循环,因为 if (strcmp(name, cursor->name) == 0) 块缺少 break.