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);
}
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);