Search code examples
cfilepointershashtable

Adding strings/lines from .dat file to a hash table in C


I've recently been trying to learn about hash-tables so i can load in lines from a .dat file. This is to reduce the number of times i spend looking through the document for certain lines. After looking through some forums, tutorial-sites and youtube videos i drafted the code seen below.

My problem so far is saving the lines from the .dat to the hash-table with void fileread(char *FILE_NAME), when I print the table I get jibberish. As far as I can tell the code I got basically just saves pointers, so in the end all pointers point to the same arraychar svaret[MAX_LIST]={};, which I've tried to make to both a 2D array and a global variable, non of of which worked. I think i know what's wrong, but i don't really know how to fix the problem. Do i have to write another type of hash code?

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

#define MAX_LIST 109
#define TABLE_SIZE 35

char FILE_MOVE_SET[]="Rubix Move Set.dat";

typedef struct move_info{
    char move_set[MAX_LIST];
    int move_length;
    struct move_info *next;
}move_info;

move_info *hash_table[TABLE_SIZE];
move_info *lookup_hash_table(char *move_set);
bool insert_hash_table(move_info *p);
int hash(char *move_set);
bool init_hash_table();
void print_table();
void fileread(char *FILE_NAME);



int main(){

    init_hash_table();

    print_table();

    fileread(FILE_MOVE_SET);

    print_table();

}

int hash(char *move_set){

    int legnth=strlen(move_set);
    unsigned int hash_value=0;

    for(int x=0;x<legnth;x++){
        hash_value+=move_set[x]*(move_set[x]+TABLE_SIZE)*x;
        hash_value=(hash_value*move_set[x])%TABLE_SIZE;
    }
    return hash_value;
}

bool init_hash_table(){
    for(int x=0;x<TABLE_SIZE;x++)
        hash_table[x]=NULL;
}

void print_table(){

    printf("TABLE START\n");

    for(int x=0;x<TABLE_SIZE;x++){

        if(hash_table[x]==NULL)
            printf("\t%i\t-----\n",x);

        else{
            printf("\t%i\t",x);
            move_info *tmp = hash_table[x];

            while(tmp!=NULL){
                printf("%s[%i] -",tmp->move_set,tmp->move_length);
                tmp=tmp->next;
            }
            printf("\n");
        }
    }
    printf("TABLE END\n");

}

bool insert_hash_table(move_info *p){

    if(p==NULL)
        return false;

    int index=hash(p->move_set);

    p->next=hash_table[index];
    hash_table[index]=p;

    return true;

}

move_info *lookup_hash_table(char *move_set){

    int index=hash(move_set);
    move_info *tmp=hash_table[index];

    while(tmp !=NULL && strcmp(tmp->move_set,move_set)!=0)
        tmp=tmp->next;

    return tmp;

}

void fileread(char *FILE_NAME){

    char svaret[MAX_LIST]={};
    move_info from_file;
    FILE *fr = fopen(FILE_NAME, "r+");

    if(fr!=NULL){
        while (fgets(svaret, MAX_LIST, fr) != NULL ){

            if(svaret[0]=='\n')
                break;

            int y=strlen(svaret)-1;
            svaret[y]='\0';

            for(int x=0;x<y+1;x++)
                from_file.move_set[x]=svaret[x];

            from_file.move_length=y;

            insert_hash_table(&from_file);
        }
    }

    fclose(fr);

}

Solution

  • You more or less give the answer in the question:

    As far as I can tell the code I got basically just saves pointers, so in the end all pointers point to the same array

    The pointer you save is a pointer to from_file from the function fileread (i.e. defined like move_info from_file;).

    This is wrong. Never save (or return) pointers to variables that are local to a function. These variables end their life once the function returns. So you have a pointer to a "dead" variable.

    In your case you need dynamic allocation. A dynamic allocated variable will "stay alive" until you decide that it's not need any longer (and then you call free).

    To use dynamic allocation you need something like:

    move_info from_file; ---> move_info *p_from_file = malloc(sizeof *p_from_file);
    

    p_from_file is now a pointer to an object of type move_info. You can save that pointer in your hash table and use the object later on - also after the function returns.

    Note: You need to modify other parts of that function to use the pointer - examples:

            from_file.move_length=y;  ---> p_from_file->move_length=y;
    
            insert_hash_table(&from_file); ---> insert_hash_table(p_from_file);