array of linked list for hash table - c

I want to know about bring the text file with 10 names and read it. 10 names are sorting by descending and forming a hash table with division method. I need to construct linked list of them. The hash table's index is number of 7.
I've tried on match pointer variable and made a hash table, but I can't do that. I'm in trouble with making hash table, inserting data, printing hash table and searching data(A function to find when I type a name.). I need to add more function..how do i made it?
#define SIZE 7
struct node {
char data[100][20];
struct node* next;
};
struct index {
struct node* head;
int count;
};
struct sum (data){
struct node* ptr;
int sum,i;
for (i=0; i<20; i++) {
ptr -> data[i] = ptr;
strcpy(sum,ptr);
}
return sum;
};
int hashFunction (int sum) {
return sum%SIZE;
}
void descend (data) {
int temp;
for(i=0;i<100;i++) {
for(j=0;j=20;j++) {
if (data[i][j+1]>data[i][j])
temp=data[i][j];
data[i][j]=data[i][j+1];
data[i][j+1]=temp;
}
}
}
int main (void) {
char data[100][20];
FILE *fp;
fp = fopen("data.txt","r");
for (int i=0; i<20; i++)
fscanf (fp,"%s",&data);
printf("%s\n",data);
}
fclose(fp);
hashTable = (struct index*)malloc(SIZE*sizeof(struct index));
descend(data);
return 0;
}

There are lot of bugs in the code, I'm just putting my possible observation. Firstly this
fscanf (fp,"%s",&data);
should be
fscanf (fp,"%s",&data[i]);
Secondly, here in descend() function inner loop condition part you are using j=20 which loops to run infinitely. This is where MACRO comes handy as this j=20 simply runs i.e if it could have ROW=j where ROW is 20 compiler produces meaningful error. This
void descend (data) { /* what is the tyep of data ? you should mention the data type */
int temp;
for(i=0;i<100;i++) { /* there are only 20 lines not 100 i.e it should be i<20 */
for(j=0;j=20;j++) { /* condition is wrong, you indented for j<20 but that too
wrong as there are supposed to be max 100 char in line
it should be j<100 */
if (data[i][j+1]>data[i][j]) /* condition is not correct */
temp=data[i][j];
data[i][j]=data[i][j+1];
data[i][j+1]=temp;
}
}
}
Correct version descend function can be
void descend (char (*data)[ROW], int col) { /* define ROW as macro with value 20 and pass the col i.e 100 */
int temp;
for(i=0;i < ROW; i++) {
for(j=0;j < col; j++) {
if (data[i][j] > data[i][j+1])
temp = data[i][j];
data[i][j] = data[i][j+1];
data[i][j+1] = temp;
}
}
}
Also check the return value of fopen() to check whether it was success r failed and do proper validation. For e.g
fp = fopen("data.txt","r");
if(fp == NULL) {
/* #TODO error handling */
fprintf(stderr,"file doesn't exist");
return 0;
}

To begin with, it looks like you should declare char data[20][100] instead of char data[100][20].
Then, inside the loop of 20 iterations, you should refer to data[i] instead of data:
for (int i=0; i<20; i++)
fscanf(fp,"%s",data[i]);
printf("%s\n",data[i]);
}
Keep in mind you're assuming that each line in your input file is at most 99-character long.
This doesn't answer the actual question I suppose, but you should by the least get all the above fixed.

Related

The edges printed does not match the nodes

I have a program that reads a file with two columns of numbers, sorts them, creates three tables, one with only the nodes (individually), one with all the edges and one that has the amount of edges for every node. The problem is that when I try to print the edges, it prints them wrong or it says it cannot find them. Through some gdb I found out that the first arrays are fine but the third stores a bunch of random numbers (or zeros) through the end. Any help would be appreciated.
The file looks like this (start/end node for each edge):
7856 8192
7754 7005
7862 1982
7862 3293
7862 4037
7862 5210
7862 5605
7862 7860
The code looks like this:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int mapcmp(const void *a,const void *b){
return ( *(int*)a - *(int*)b );
}
int mapdoublesize(int** map,int nodes){
int* new_array=malloc(nodes*2*sizeof(int));
if(new_array==NULL){
printf("Error allocating memory\n");
abort();
}
nodes*=2;
for(int i=0;i<nodes;i++){
new_array[i]=(*map)[i];
}
free(*map);
*map=new_array;
return nodes;
}
typedef struct {
int start;
int end;
} path;
int cmp(const void *a,const void *b){
int l=((path*)a)->start;
int r=((path*)b)->start;
if(l>r)
return 1;
if(l<r)
return -1;
if(l==r)
return 0;
}
int doublesize(path** array,int n){
path* new_array=malloc(n*2*sizeof(path));
if(new_array==NULL){
printf("Error allocating memory\n");
abort();
}
for(int i=0;i<n;i++){
new_array[i]=(*array)[i];
}
free(*array);
*array=new_array;
n*=2;
return n;
}
int main()
{
int maxsize=10;
int test;
path* array=malloc(maxsize*sizeof(path));
if(array==NULL) {
printf("Error allocating memory\n");
abort();
}
FILE* fd=fopen("Wiki-Vote.txt","r");
if(fd==NULL) {
printf("Error opening file\n");
abort();
}
char buff[200];
int counter=0;
char c;
while(fgets(buff,200,fd)) {
c=buff[0];
if(c=='#') {
continue;
}
sscanf(buff,"%d%d",&array[counter].start,&array[counter].end);
counter++;
if(counter==maxsize){
maxsize=doublesize(&array,maxsize);
}
}
int i;
maxsize=counter;
counter=0;
qsort(&array[0],maxsize,sizeof(path),cmp);
counter=0;
int nodes=10;
int* map=malloc(nodes*sizeof(int));
if(map==NULL){
printf("Error allocating memory\n");
abort();
}
for(i=0;i<maxsize;i++){
if(map[counter-1]==array[i].start)
continue;
map[counter]=array[i].start;
counter++;
if(counter==nodes){
nodes=mapdoublesize(&map,nodes);
}
}
int j;
for(i=0;i<maxsize;i++){
for(j=0;j<counter;j++){
if(map[j]==array[i].end)
break;
}
if(j!=counter)
continue;
map[counter]=array[i].end;
counter++;
if(counter==nodes)
nodes=mapdoublesize(&map,nodes);
}
nodes=counter;
qsort(&map[0],nodes,sizeof(int),mapcmp);
int* arraynodes=malloc(nodes*sizeof(int));
int* arrayedges=malloc(maxsize*sizeof(int));
if(arraynodes==NULL||arrayedges==NULL){
printf("Error allocating memory\n");
abort();
}
counter=1;
arraynodes[0]=0;
for(i=0;i<maxsize;i++){
arrayedges[i]=array[i].end;
if(array[i].start!=array[i+1].start){
arraynodes[counter]=i;
counter++;
}
}
int x;
printf("give number to search: ");
scanf("%d",&x);
for(i=0;i<nodes;i++){
if(x==map[i]){
printf("found \n");
break;
}
}
if(i==nodes){
printf("not found \n");
abort();
}
for(j=arraynodes[i];j<arraynodes[i+1];j++){
printf("%d\n",arrayedges[j]);
}
free(arraynodes);
free(arrayedges);
free(map);
fclose(fd);
free(array);
return 0;
}
Core answer:
As I understand your intention, you want arraynodes to hold for each node index the offset in the edge list where the edges for that node start.
You iterate over the edge list and every time the starting point changes, you store the current offset in arraynodes. This is flawed, because not all nodes are the starting point of an edge. So if your edge list has an edge from node 5 -> 7 and then an edge from 6 -> 7 then you will register the change of the starting point from 5 to 6, but you will store the current offset at the beginning of arraynodes and not for the 5th node.
To fix this, instead do this: Keep an offset into the edge list, initially zero. Iterate over the nodes, for each node store the current offset into arraynodes. Then increment the offset as long as the starting point of the edge at the current offset is equal to the current node. This way arraynodes will tell you for each node index, at which index in the edge list the edges starting at this node are stored.
/**
* Assumption: Edges are sorted by their starting point.
*/
int edge_count = maxsize;
int edge_offset = 0;
/**
* For each node:
*
* - Store current edge_offset in arraynodes
* - Increment edge_offset as long as the start point
* of the edge at that offset matches the current node.
*/
for (int i = 0; i < nodes; i++) {
int current_node = map[i];
arraynodes[i] = edge_offset;
while (edge_offset < edge_count && array[edge_offset].start == current_node) {
edge_offset++;
}
}
/**
* Copy end-points of edges to arrayedges.
*
* You don't really need this, you could also directly
* access the end-points in your output loop ...
*/
for (int i = 0; i < edge_count; i++) {
arrayedges[i] = array[i].end;
}
Memory safety issues:
There are a several memory safety issues in your code:
Buffer underflow: In the first pass of the loop, counter is zero, so map[counter-1] goes out of bounds.
counter = 0;
int nodes = 10;
int *map = malloc(nodes * sizeof(int));
if (map == NULL) {
printf("Error allocating memory\n");
abort();
}
for (i = 0; i < maxsize; i++) {
if (map[counter - 1] == array[i].start)
continue;
Buffer overflow: When you initialize the map, you want to double its size when it's full. However, in mapdoublesize when you copy the data from the old map to the new map, you iterate over the whole new map, so the second half of this loop reads past the bounds of the old map:
nodes *= 2;
for (int i = 0; i < nodes; i++) {
new_array[i] = (*map)[i];
}
Buffer overflow: In the last iteration of this loop: The access to array[i+1] is out of bounds:
for (i = 0; i < maxsize; i++) {
arrayedges[i] = array[i].end;
if (array[i].start != array[i + 1].start) {
Buffer overflow: In your output loop, if i is the last node, your access to arraynodes[i+1] goes out of bounds:
for (j = arraynodes[i]; j < arraynodes[i + 1]; j++) {
I do not guarantee that I found all memory safety issues. There might very well be more. I would advice you to improve the structuring and documentation of your program: Break down your program into smaller functions that do one step and document the assumptions and preconditions of this step (i.e. what are the bound of the array you are accessing?). Give the variables names that cleary describe their purpose, do not reuse variables. This should make it easier for you to spot these kinds of errors. Also I would advice you to use tools to check for memory safety issues. GCC and Clang both have a feature called ASAN that will automatically insert debug code into your binary that will detect and report memory safety issues when you run your program. You can enable this by compiling with -fsanitize=address (reference). Another tool with a similar scope would be Valgrind (reference). These programs cannot find all errors of course, since they only do dynamic analysis of the code that is actually executed. If there is a bug in some branch of your program that is not reached by the current execution, it will not be detected. So you still do not get around taking a careful look at your program.

Why is Valgrind finding errors in this hash table test case?

I took it upon myself to develop a concurrent generic hash table in C.
Relevant contents of hash_table.h:
typedef struct list_node {
void * data;
struct list_node * next;
} list_node_t;
typedef struct hash_table {
int max_size;
int count;
list_node_t * * elements;
pthread_rwlock_t * locks;
pthread_rwlock_t global_table_lock;
hash_table_compare_function compare;
hash_table_hash_function hash;
} hash_table_t;
Relevant contents of hash_table.c:
#define LOCK_RD(lock) pthread_rwlock_rdlock(&lock);
#define LOCK_WR(lock) pthread_rwlock_wrlock(&lock);
#define UNLOCK(lock) pthread_rwlock_unlock(&lock);
bool
hash_table_remove(hash_table_t * table, void * element)
{
int hash_value = table->hash(element);
list_node_t * node, * prev;
LOCK_WR(table->locks[hash_value]);
node = table->elements[hash_value];
prev = NULL;
while (node) {
if (!table->compare(node->data, element)) {
// value is first item in the list
if (node == table->elements[hash_value]) {
table->elements[hash_value] = node->next;
free(node);
UNLOCK(table->locks[hash_value]);
LOCK_WR(table->global_table_lock);
table->count--;
UNLOCK(table->global_table_lock);
return true;
} else {
// link previous node with one after current
prev->next = node->next;
free(node);
UNLOCK(table->locks[hash_value]);
LOCK_WR(table->global_table_lock);
table->count--;
UNLOCK(table->global_table_lock);
return true;
}
}
prev = node;
node = node->next;
}
UNLOCK(table->locks[hash_value]);
return false;
}
I wrote a test case which uses strings, in which this is the relevant code:
#include "hashtable.h"
#define NUM_THREADS 2
#define NUM_STRINGS 154560
#define NUM_LOOKUPS 10000
void *
do_work(void * data)
{
int thread_id = *(int*)data;
// write "threadX.txt" to filename, where X is the given thread id
char filename[64];
strcpy(filename, "thread");
char thread_id_str[4];
sprintf(thread_id_str, "%d", thread_id);
strcat(filename, thread_id_str);
strcat(filename, ".txt");
FILE * file = fopen(filename, "r");
char buffer[128];
int i, num_str_per_thread = NUM_STRINGS / NUM_THREADS;
char * str_array[num_str_per_thread];
for (i = 0; i < num_str_per_thread; i++) {
fgets(buffer, 128, file);
str_array[i] = calloc((strlen(buffer) + 1), sizeof(char));
strcpy(str_array[i], buffer);
}
fclose(file);
for (i = 0; i < num_str_per_thread; i++)
hash_table_insert(table, str_array[i]);
for (i = 0; i < NUM_LOOKUPS; i++)
hash_table_contains(table, str_array[rand() % num_str_per_thread]);
for (i = 0; i < num_str_per_thread / 2; i++)
hash_table_remove(table, str_array[rand() % num_str_per_thread]);
//sleep(2); NOTE: no read errors reported if I leave this sleep() here.
for (i = 0; i < num_str_per_thread; i++)
if (str_array[i])
free(str_array[i]);
return NULL;
}
void
create_workers()
{
pthread_t threads[NUM_THREADS];
int ids[NUM_THREADS];
int i;
for (i = 0; i < NUM_THREADS; i++)
ids[i] = i + 1;
for (i = 0; i < NUM_THREADS; i++)
pthread_create(&threads[i], NULL, do_work, (void*)&ids[i]);
for (i = 0; i < NUM_THREADS; i++)
pthread_join(threads[i], NULL);
}
The test case is supposed to work as follows: there are two files, thread1.txt and thread2.txt, each containing unique strings I have generated beforehand. I create two threads, and each will read from a file and store each string on an array of strings called str_array. They will then insert all these strings into the hash table and perform random searches (hash_table_contains) and deletions (hash_table_remove). Then, each will free their respective array of strings. However, when I run this test case, Valgrind reports the following:
Please note that there are no memory leaks. What I get from these errors is that a thread is, upon calling hash_table_remove, attempting to free memory already freed by free(str_array[i]). However, that makes no sense, since hash_table_remove is called before free(str_array[i]. I can't figure out what's giving me these invalid reads.
Thank you in advance!
Here, your thread removes at most half the strings it inserted:
for (i = 0; i < num_str_per_thread / 2; i++)
hash_table_remove(table, str_array[rand() % num_str_per_thread]);
(in fact, it is most likely to remove about 39% of the strings it inserted).
Then, it goes on to free all the strings it inserted:
for (i = 0; i < num_str_per_thread; i++)
if (str_array[i])
free(str_array[i]);
However, at least half (and most likely ~61%) of those strings are still in the hash table, where the other threads will try to compare them as they scan through the chained hash bucket entries. That's your use-after-free error.
Instead of freeing all the strings, you could free them as you remove them:
for (i = 0; i < num_str_per_thread / 2; i++)
{
int str_index = rand() % num_str_per_thread;
if (str_array[str_index])
{
hash_table_remove(table, str_array[str_index]);
free(str_array[str_index]);
str_array[str_index] = NULL;
}
}
At this point, the non-NULL entries in str_array[] are the strings still present in the hash table. You can't free them until they're removed from the hash table (or the hash table is no longer in use).
The fact that your test case got this wrong is a good indicator that the ergonomics of your interface are not as good as they could be. You should probably consider a design in which the ownership of the strings inserted is transferred to the hash table, so that hash_table_remove() is itself responsible for freeing the string.

c Struct Array, Storing string and its occurrence and writing it to a file

so I'm having a little problem with my struct array not doing what its supposed to. I get no compiler warnings or errors when building the program.
int Array_Size=0;;
int Array_Index=0;
FILE *Writer;
struct WordElement
{
int Count;
char Word[50];
};
struct WordElement *StructPointer; //just a pointer to a structure
int Create_Array(int Size){
StructPointer = (struct WordElement *) malloc(Size * sizeof(StructPointer));
Array_Size = Size;
return 0;
}
int Add_To_Array(char Word[50]){
int Word_Found=0;
for(int i=0; i <= Array_Size && Word_Found!=1; i++)
{
if(strcmp(StructPointer[i].Word, Word)) // This should only run if the word exists in struct array
{
StructPointer[i].Count++;
Word_Found=1;
}
}
if(Word_Found==0) // if the above if statement doesnt evualate, this should run
{
strcpy(StructPointer[Array_Index].Word, Word); //copying the word passed by the main function to the struct array at a specific index
printf("WORD: %s\n", StructPointer[Array_Index].Word); // printing it just to make sure it got copied correctly
Array_Index++;
}
return 0;
}
int Print_All(char File_Name[50])
{
Writer = fopen(File_Name, "w");
printf("Printing starts now: \n");
for(int i=0; i < Array_Size; i++)
{
fprintf(Writer, "%s\t\t%d\n",StructPointer[i].Word, StructPointer[i].Count);
}
free(StructPointer);
return 0;
}
These functions get called from a different file, The Add_To_Array is called when the program reads a new word form the text file. That function is supposed to check if the word already exists in the struct array and if it does, it should just increment the counter. If it doesn't, then it adds it.
The Print_All function is called after all the words have been stored in the struct array. Its supposed to loop through them and print each word and their occurrence. In the text file, there are 2 of every words but my program outputs:
this 13762753
document -1772785369
contains 1129268256
two 6619253
of 5701679
every 5570645
word 3342389
doccontains 5374021
I don't know what to make of this as im really new to C programming... It's probably worth mentioning the if(Word_Foun==0) doesn't execute
StructPointer = malloc(Size * sizeof(*StructPointer));
This will be the correct allocation. Otherwise you will have erroneous behavior in your code. Also check the return value of malloc.
StructPointer = malloc(Size * sizeof(*StructPointer));
if(NULL == StructPointer){
perror("malloc failure");
exit(EXIT_FAILURE);
}
You are allocating for struct WordElement not a for a pointer to it. You already have a pointer to struct WordElement all that you needed was memory for a struct WordElement.
Also in the loop you are accessing array index out of bound
for(int i=0; i <= Array_Size && Word_Found!=1; i++)
^^^
It will be i < Array_Size.
In case match occurs you want to set the variable Word_found to 1.
if(strcmp(StructPointer[i].Word, Word) == 0){
/* it macthed */
}
Also Writer = fopen(File_Name, "w"); you should check the return value of fopen.
if(Writer == NULL){
fprintf(stderr,"Error in file opening");
exit(EXIT_FAILURE);
}
Also when you are increasing the Array_index place a check whether it might access the array index out of bound.
The more global variable you use for achieving a small task would make it more difficult to track down a bug. It is always problematic because the places from which data might change is scattered - making it difficult to manage.

How to read dataset from text file to a 2D matrix

I have a dataset of form
0.547,0.797,2.860,1.398,Sharp-Right-Turn
0.541,0.786,2.373,1.919,Sharp-Right-Turn
0.549,0.784,2.370,1.930,Sharp-Right-Turn
0.983,0.780,2.373,1.701,Move-Forward
0.984,0.780,2.372,1.700,Move-Forward
0.983,0.780,2.378,1.602,Move-Forward
0.983,0.780,2.381,1.701,Move-Forward
.
.
ROWS=5456, COL 5
Its easy in MATLAB to load the text file into a data matrix. But am struggling in C.
I tried this code
int main()
{
struct node {
float at1;
float at2;
float at3;
float at4;
char at5[30];
} record[ROW][COL];
FILE *file;
int i, j;
memset(record, 0, sizeof(record));
file = fopen("sensor.txt", "r");
if (file == NULL) {
printf("File does not exist!");
} else {
for (i = 0; i < ROW; ++i) {
for (j = 0; j < COL; ++j) {
fscanf(file, "%f,%f,%f,%f,%s", &record[i][j].at1, &record[i][j].at2, &record[i][j].at3, &record[i][j].at4, &record[i][j].at5);
}
}
}
fclose(file);
for (i = 0; i < ROW; ++i)
for (j = 0; j < COL; ++j) {
printf("%f\t%f\t%f\t%f\t%s\n", record[i][j].at1, record[i][j].at2, record[i][j].at3, record[i][j].at4, record[i][j].at5);
}
return 0;
}
I am getting infinite rows and 4 cols of 0.000000 only.
I want to save the first four columns in one matrix and last column as another column matrix. Could I do that?
I have to build a classifier which I easily did in MATLAB without using predefined functions but reading data in C is hampering my code.
I know this might be a repeated question, but I tried solutions in other threads, they are not working on my dataset.
First of all you have defined a record holding all your fields, that together forms each row. This means that when you read you have all values for a row so the struct dimension should be the maximum record available that is a monodimensional array of structures record.
But you cannot allocate such an huge struct on the stack, it will overflow, it's better to allocate it in dynamic memory:
struct node {
float at1;
float at2;
float at3;
float at4;
char at5[30];
} record;
struct node *record = malloc(sizeof(struct node) * MAXRECORDS);
Another error is in the scanf, the last field of the structure record is already a pointer to char, so you don't need to dereference it.
This is a working code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXRECORDS 10
int main(int argc, char *argv[])
{
struct node {
float at1;
float at2;
float at3;
float at4;
char at5[30];
};
struct node *record = malloc(sizeof(struct node) * MAXRECORDS);
FILE *file;
int nRecords = 0;
memset(record, 0, sizeof(record));
file = fopen("sensor.txt", "r");
if (file == NULL)
{
printf("File does not exist!");
}
else
{
while (EOF != fscanf(file, "%f,%f,%f,%f,%s", &record[nRecords].at1, &record[nRecords].at2,
&record[nRecords].at3, &record[nRecords].at4, record[nRecords].at5) && nRecords<MAXRECORDS)
{
nRecords++;
}
}
fclose(file);
for (int i = 0; i < nRecords; ++i)
{
printf("%f\t%f\t%f\t%f\t%s\n",
record[i].at1, record[i].at2,
record[i].at3, record[i].at4, record[i].at5);
}
return 0;
}
In a 'real' application you want dimension the array to some large enough value, and when you reach the end of the allocated space you can reallocate it for other data. This allows you to read a file of how many entries you want without knowing their number before the reading.
P.S. I added the check for maximum number of record to read. But this remain a sample, many checks are still missing i.e. I don't check value returned by malloc.

Insert function of Hashtable in C

So, I have the functions. How can I insert numbers in the Hashtable? A for that goes until the size of the table? I don't know what goes inside the for, if it is exists.
#include <stdio.h>
//Structure
typedef struct Element {
int key;
int value;
} Element;
typedef struct HashTable {
Element *table[11];
} HashTable;
//Create an empty Hash
HashTable* createHashTable() {
HashTable *Raking = malloc(sizeof(HashTable));
int i;
for (i = 0; i < 11; i++) {
Raking->table[i] = NULL;
}
return Raking;
}
//Insert element
void insertElement(HashTable *Raking, int key, int value) {
int h = hashFunction(key);
while(Raking->table[h] != NULL) {
if(Raking->table[h]->key == key) {
Raking->table[h]->value = value;
break;
}
h = (h + 1) % 11;
}
if(Raking->table[h] == NULL) {
Element *newElement = (Element*) malloc(sizeof(Element));
newElement->key = key;
newElement->value = value;
Raking->table[h] = newElement;
}
}
int main() {
HashTable * Ranking = createHashTable();
/** ??? **/
}
Could someone explain to me how to write my main function with these structures? In this case I'm fixing the number of elements in this table, right? (table [11]) What could I do for the user to determine the size of the hash table? is it possible? Or should I set the size?
I've added comments and changes to your code that I feel will be of use to you. I've also adapted it so that size is not hardcoded. Finally I free all the malloc-ed statements.
This compiles without errors and I've tested it for memory leaks and other errors using valgrind and found no complaints.
Let me know if something is not clear and the comments fail to explain it. I've tried to stick to your code as much as possible but I've not had a chance to test the functionality properly.
#include <stdio.h>
#include <stdlib.h>
//Structure
typedef struct Element {
int key;
int value;
} Element; /* you had a syntax error here */
typedef struct HashTable {
int size; /* we will need the size for the traversal */
Element *table; /* leave it as a pointer */
} HashTable; /* a syntax error here too */
HashTable* createHashTable(int size) {
HashTable *Ranking = malloc(sizeof(HashTable));
/* set the pointer to point to a dynamic array of size 'size' */
/* this way you don't have to hardcode the size */
Ranking->table = malloc(sizeof(Element) * size);
Ranking->size = size;
/* initialisation is a bit different because we don't have pointers here */
/* only table is a pointer, not its elements */
int i;
for (i = 0; i < size; i++) {
Ranking->table[i].key = 0;
Ranking->table[i].value = 0;
}
return Ranking;
}
/* I implemented a fake hashFunction just to test the code */
/* all it does is make sure the key does not exceed the size of the table */
int hashFunction(int key, int size)
{
return (key % size);
}
//Insert element
void insertElement(HashTable *Ranking, int key, int value) {
int h = hashFunction(key, Ranking->size);
int i = 0;
/* if hash is full and key doesn't exist your previous loop would have gone on forever, I've added a check */
/* also notice that I check if table[h] has empty key, not if it's null as this is not a pointer */
while(Ranking->table[h].key != 0 && (i < Ranking->size)) {
if(Ranking->table[h].key == key) {
Ranking->table[h].value = value;
return; /* break is intended to quit the loop, but actually we want to exit the function altogether */
}
h = (h + 1) % Ranking->size; /* changed 11 to the size specified */
i++; /* advance the loop index */
}
/* okay found a free slot, store it there */
if(Ranking->table[h].key == 0) {
/* we now do direct assignment, no need for pointers */
Ranking->table[h].key = key;
Ranking->table[h].value = value;
}
}
int main() {
int size = 0;
scanf(" %d", &size);
HashTable *Ranking = createHashTable(size);
insertElement(Ranking, 113, 10); /* this is just a test, 113 will be hashed to be less than size */
/* we free everything we have malloc'ed */
free(Ranking->table);
free(Ranking);
return 0;
}

Resources