C hashtable implementation











up vote
3
down vote

favorite












The following code is an implementation of an hashtable in C.




hashTable.c:




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

#include "hashTable.h"

int hashCode(int key) {
return key % SIZE;
}

/*
By given key returns a pointer to a DataItem with the same key
Input: Pointer to hashArray array, int key value
Output: If key found - the pointer to a DataItem else NULL
*/
DataItem *getValueByKey (DataItem** hashArray, int key) {
/* Get the hash */
int hashIndex = hashCode(key);

/* Move in array until an empty */
while(hashArray[hashIndex] != NULL) {

if(hashArray[hashIndex]->key == key)
return hashArray[hashIndex];

/* Go to next cell */
++hashIndex;

/* Wrap around the table */
hashIndex %= SIZE;
}

return NULL;
}

/*
Adding a DataItem to a hashArray
Input: Pointer to hashArray array, int key value, char* (string) data value
Output: None
*/
void putValueForKey (DataItem** hashArray, int key, char *data) {
/* Get the hash */
int hashIndex = hashCode(key);

DataItem *item = (DataItem*) malloc(sizeof(DataItem));
item->data = data;
item->key = key;

/* Move in array until an empty or deleted cell */
while(hashArray[hashIndex] != NULL) {
/* Go to next cell */
++hashIndex;

/* Wrap around the table */
hashIndex %= SIZE;
}

hashArray[hashIndex] = item;
}

/*
Deleting a DataItem node from an hash array
Input: Pointer to hashArray array, pointer to the item we want to delete
Output: The deleted item pointer
*/
DataItem* deleteHash (DataItem** hashArray, DataItem* item) {
int key;
int hashIndex;
if (item == NULL)
{
return NULL;
}

key = item->key;

/* Get the hash */
hashIndex = hashCode(key);

/* Move in array until an empty */
while(hashArray[hashIndex] != NULL) {

if(hashArray[hashIndex]->key == key) {
DataItem* temp = hashArray[hashIndex];

/* Assign a dummy item at deleted position */
hashArray[hashIndex] = NULL;
return temp;
}

/* Go to next cell */
++hashIndex;

/* Wrap around the table */
hashIndex %= SIZE;
}

return NULL;
}

/*
displaying an hash array
Input: Pointer to hashArray array
Output: None
*/
void displayHashTable (DataItem** hashArray) {
int i = 0;

for (i = 0; i < SIZE; i++) {

if (hashArray[i] != NULL)
printf(" (%d,%s)",hashArray[i]->key,hashArray[i]->data);
else
printf(" ~~ ");
}

printf("n");
}

/*
Freeing an hash array
Input: Pointer to hashArray array
Output: None
*/
void freeHashTable (DataItem** hashArray) {
int i = 0;
for (i = 0; i < SIZE; ++i)
{
if (hashArray[i] != NULL) {
free(hashArray[i]);
}
}
}

/*
Initialize an hash array by setting all the nodes to NULL
Input: Pointer to hashArray array
Output: None
*/
void initializeHashArray (DataItem** hashArray) {
int i = 0;
for (i = 0; i < SIZE; i++) {
hashArray[i] = NULL;
}
}

int main() {
DataItem* hashArray[SIZE];
initializeHashArray(hashArray);

putValueForKey(hashArray, 100, "MAIN");
putValueForKey(hashArray, 107, "LOOP");
putValueForKey(hashArray, 121, "END");
putValueForKey(hashArray, 122, "STR");
putValueForKey(hashArray, 129, "LENGTHHHHHHHHHHHHHHHHHHHHH");
putValueForKey(hashArray, 132, "K");
putValueForKey(hashArray, 133, "M1");


displayHashTable(hashArray);
DataItem* item = getValueByKey(hashArray, 100);

if (item != NULL) {
printf("Element found: %sn", item->data);
}
else {
printf("Element not foundn");
}

deleteHash(hashArray, item);
item = getValueByKey(hashArray, 100);

if (item != NULL) {
printf("Element found: %sn", item->data);
}
else {
printf("Element not foundn");
}
displayHashTable(hashArray);

freeHashTable(hashArray);
}


I believe this code is well commented and very understandable, if you think it's not please let me know.



The main is there just for testing and will not be part of the final code.



My main concerns are:




  1. The free function (freeHashTable) because I don't know how to test it so I don't know if it's working.


  2. The while loops that might get into an infinite loop condition for some reason.



Also this is the first time I'm trying to implement hash table, so if I'm missing something from the logical aspect of hash code explanation will be very welcomed.




hashTable.h:




#define SIZE 20

struct DataItem {
char *data;
int key;
}typedef DataItem;

DataItem *getValueByKey (DataItem** hashArray, int key);
void putValueForKey (DataItem** hashArray, int key, char *data);
DataItem* deleteHash (DataItem** hashArray, DataItem* item);
void displayHashTable (DataItem** hashArray);
void freeHashTable (DataItem** hashArray);
void initializeHashArray (DataItem** hashArray);


Thanks in advance!










share|improve this question


























    up vote
    3
    down vote

    favorite












    The following code is an implementation of an hashtable in C.




    hashTable.c:




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

    #include "hashTable.h"

    int hashCode(int key) {
    return key % SIZE;
    }

    /*
    By given key returns a pointer to a DataItem with the same key
    Input: Pointer to hashArray array, int key value
    Output: If key found - the pointer to a DataItem else NULL
    */
    DataItem *getValueByKey (DataItem** hashArray, int key) {
    /* Get the hash */
    int hashIndex = hashCode(key);

    /* Move in array until an empty */
    while(hashArray[hashIndex] != NULL) {

    if(hashArray[hashIndex]->key == key)
    return hashArray[hashIndex];

    /* Go to next cell */
    ++hashIndex;

    /* Wrap around the table */
    hashIndex %= SIZE;
    }

    return NULL;
    }

    /*
    Adding a DataItem to a hashArray
    Input: Pointer to hashArray array, int key value, char* (string) data value
    Output: None
    */
    void putValueForKey (DataItem** hashArray, int key, char *data) {
    /* Get the hash */
    int hashIndex = hashCode(key);

    DataItem *item = (DataItem*) malloc(sizeof(DataItem));
    item->data = data;
    item->key = key;

    /* Move in array until an empty or deleted cell */
    while(hashArray[hashIndex] != NULL) {
    /* Go to next cell */
    ++hashIndex;

    /* Wrap around the table */
    hashIndex %= SIZE;
    }

    hashArray[hashIndex] = item;
    }

    /*
    Deleting a DataItem node from an hash array
    Input: Pointer to hashArray array, pointer to the item we want to delete
    Output: The deleted item pointer
    */
    DataItem* deleteHash (DataItem** hashArray, DataItem* item) {
    int key;
    int hashIndex;
    if (item == NULL)
    {
    return NULL;
    }

    key = item->key;

    /* Get the hash */
    hashIndex = hashCode(key);

    /* Move in array until an empty */
    while(hashArray[hashIndex] != NULL) {

    if(hashArray[hashIndex]->key == key) {
    DataItem* temp = hashArray[hashIndex];

    /* Assign a dummy item at deleted position */
    hashArray[hashIndex] = NULL;
    return temp;
    }

    /* Go to next cell */
    ++hashIndex;

    /* Wrap around the table */
    hashIndex %= SIZE;
    }

    return NULL;
    }

    /*
    displaying an hash array
    Input: Pointer to hashArray array
    Output: None
    */
    void displayHashTable (DataItem** hashArray) {
    int i = 0;

    for (i = 0; i < SIZE; i++) {

    if (hashArray[i] != NULL)
    printf(" (%d,%s)",hashArray[i]->key,hashArray[i]->data);
    else
    printf(" ~~ ");
    }

    printf("n");
    }

    /*
    Freeing an hash array
    Input: Pointer to hashArray array
    Output: None
    */
    void freeHashTable (DataItem** hashArray) {
    int i = 0;
    for (i = 0; i < SIZE; ++i)
    {
    if (hashArray[i] != NULL) {
    free(hashArray[i]);
    }
    }
    }

    /*
    Initialize an hash array by setting all the nodes to NULL
    Input: Pointer to hashArray array
    Output: None
    */
    void initializeHashArray (DataItem** hashArray) {
    int i = 0;
    for (i = 0; i < SIZE; i++) {
    hashArray[i] = NULL;
    }
    }

    int main() {
    DataItem* hashArray[SIZE];
    initializeHashArray(hashArray);

    putValueForKey(hashArray, 100, "MAIN");
    putValueForKey(hashArray, 107, "LOOP");
    putValueForKey(hashArray, 121, "END");
    putValueForKey(hashArray, 122, "STR");
    putValueForKey(hashArray, 129, "LENGTHHHHHHHHHHHHHHHHHHHHH");
    putValueForKey(hashArray, 132, "K");
    putValueForKey(hashArray, 133, "M1");


    displayHashTable(hashArray);
    DataItem* item = getValueByKey(hashArray, 100);

    if (item != NULL) {
    printf("Element found: %sn", item->data);
    }
    else {
    printf("Element not foundn");
    }

    deleteHash(hashArray, item);
    item = getValueByKey(hashArray, 100);

    if (item != NULL) {
    printf("Element found: %sn", item->data);
    }
    else {
    printf("Element not foundn");
    }
    displayHashTable(hashArray);

    freeHashTable(hashArray);
    }


    I believe this code is well commented and very understandable, if you think it's not please let me know.



    The main is there just for testing and will not be part of the final code.



    My main concerns are:




    1. The free function (freeHashTable) because I don't know how to test it so I don't know if it's working.


    2. The while loops that might get into an infinite loop condition for some reason.



    Also this is the first time I'm trying to implement hash table, so if I'm missing something from the logical aspect of hash code explanation will be very welcomed.




    hashTable.h:




    #define SIZE 20

    struct DataItem {
    char *data;
    int key;
    }typedef DataItem;

    DataItem *getValueByKey (DataItem** hashArray, int key);
    void putValueForKey (DataItem** hashArray, int key, char *data);
    DataItem* deleteHash (DataItem** hashArray, DataItem* item);
    void displayHashTable (DataItem** hashArray);
    void freeHashTable (DataItem** hashArray);
    void initializeHashArray (DataItem** hashArray);


    Thanks in advance!










    share|improve this question
























      up vote
      3
      down vote

      favorite









      up vote
      3
      down vote

      favorite











      The following code is an implementation of an hashtable in C.




      hashTable.c:




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

      #include "hashTable.h"

      int hashCode(int key) {
      return key % SIZE;
      }

      /*
      By given key returns a pointer to a DataItem with the same key
      Input: Pointer to hashArray array, int key value
      Output: If key found - the pointer to a DataItem else NULL
      */
      DataItem *getValueByKey (DataItem** hashArray, int key) {
      /* Get the hash */
      int hashIndex = hashCode(key);

      /* Move in array until an empty */
      while(hashArray[hashIndex] != NULL) {

      if(hashArray[hashIndex]->key == key)
      return hashArray[hashIndex];

      /* Go to next cell */
      ++hashIndex;

      /* Wrap around the table */
      hashIndex %= SIZE;
      }

      return NULL;
      }

      /*
      Adding a DataItem to a hashArray
      Input: Pointer to hashArray array, int key value, char* (string) data value
      Output: None
      */
      void putValueForKey (DataItem** hashArray, int key, char *data) {
      /* Get the hash */
      int hashIndex = hashCode(key);

      DataItem *item = (DataItem*) malloc(sizeof(DataItem));
      item->data = data;
      item->key = key;

      /* Move in array until an empty or deleted cell */
      while(hashArray[hashIndex] != NULL) {
      /* Go to next cell */
      ++hashIndex;

      /* Wrap around the table */
      hashIndex %= SIZE;
      }

      hashArray[hashIndex] = item;
      }

      /*
      Deleting a DataItem node from an hash array
      Input: Pointer to hashArray array, pointer to the item we want to delete
      Output: The deleted item pointer
      */
      DataItem* deleteHash (DataItem** hashArray, DataItem* item) {
      int key;
      int hashIndex;
      if (item == NULL)
      {
      return NULL;
      }

      key = item->key;

      /* Get the hash */
      hashIndex = hashCode(key);

      /* Move in array until an empty */
      while(hashArray[hashIndex] != NULL) {

      if(hashArray[hashIndex]->key == key) {
      DataItem* temp = hashArray[hashIndex];

      /* Assign a dummy item at deleted position */
      hashArray[hashIndex] = NULL;
      return temp;
      }

      /* Go to next cell */
      ++hashIndex;

      /* Wrap around the table */
      hashIndex %= SIZE;
      }

      return NULL;
      }

      /*
      displaying an hash array
      Input: Pointer to hashArray array
      Output: None
      */
      void displayHashTable (DataItem** hashArray) {
      int i = 0;

      for (i = 0; i < SIZE; i++) {

      if (hashArray[i] != NULL)
      printf(" (%d,%s)",hashArray[i]->key,hashArray[i]->data);
      else
      printf(" ~~ ");
      }

      printf("n");
      }

      /*
      Freeing an hash array
      Input: Pointer to hashArray array
      Output: None
      */
      void freeHashTable (DataItem** hashArray) {
      int i = 0;
      for (i = 0; i < SIZE; ++i)
      {
      if (hashArray[i] != NULL) {
      free(hashArray[i]);
      }
      }
      }

      /*
      Initialize an hash array by setting all the nodes to NULL
      Input: Pointer to hashArray array
      Output: None
      */
      void initializeHashArray (DataItem** hashArray) {
      int i = 0;
      for (i = 0; i < SIZE; i++) {
      hashArray[i] = NULL;
      }
      }

      int main() {
      DataItem* hashArray[SIZE];
      initializeHashArray(hashArray);

      putValueForKey(hashArray, 100, "MAIN");
      putValueForKey(hashArray, 107, "LOOP");
      putValueForKey(hashArray, 121, "END");
      putValueForKey(hashArray, 122, "STR");
      putValueForKey(hashArray, 129, "LENGTHHHHHHHHHHHHHHHHHHHHH");
      putValueForKey(hashArray, 132, "K");
      putValueForKey(hashArray, 133, "M1");


      displayHashTable(hashArray);
      DataItem* item = getValueByKey(hashArray, 100);

      if (item != NULL) {
      printf("Element found: %sn", item->data);
      }
      else {
      printf("Element not foundn");
      }

      deleteHash(hashArray, item);
      item = getValueByKey(hashArray, 100);

      if (item != NULL) {
      printf("Element found: %sn", item->data);
      }
      else {
      printf("Element not foundn");
      }
      displayHashTable(hashArray);

      freeHashTable(hashArray);
      }


      I believe this code is well commented and very understandable, if you think it's not please let me know.



      The main is there just for testing and will not be part of the final code.



      My main concerns are:




      1. The free function (freeHashTable) because I don't know how to test it so I don't know if it's working.


      2. The while loops that might get into an infinite loop condition for some reason.



      Also this is the first time I'm trying to implement hash table, so if I'm missing something from the logical aspect of hash code explanation will be very welcomed.




      hashTable.h:




      #define SIZE 20

      struct DataItem {
      char *data;
      int key;
      }typedef DataItem;

      DataItem *getValueByKey (DataItem** hashArray, int key);
      void putValueForKey (DataItem** hashArray, int key, char *data);
      DataItem* deleteHash (DataItem** hashArray, DataItem* item);
      void displayHashTable (DataItem** hashArray);
      void freeHashTable (DataItem** hashArray);
      void initializeHashArray (DataItem** hashArray);


      Thanks in advance!










      share|improve this question













      The following code is an implementation of an hashtable in C.




      hashTable.c:




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

      #include "hashTable.h"

      int hashCode(int key) {
      return key % SIZE;
      }

      /*
      By given key returns a pointer to a DataItem with the same key
      Input: Pointer to hashArray array, int key value
      Output: If key found - the pointer to a DataItem else NULL
      */
      DataItem *getValueByKey (DataItem** hashArray, int key) {
      /* Get the hash */
      int hashIndex = hashCode(key);

      /* Move in array until an empty */
      while(hashArray[hashIndex] != NULL) {

      if(hashArray[hashIndex]->key == key)
      return hashArray[hashIndex];

      /* Go to next cell */
      ++hashIndex;

      /* Wrap around the table */
      hashIndex %= SIZE;
      }

      return NULL;
      }

      /*
      Adding a DataItem to a hashArray
      Input: Pointer to hashArray array, int key value, char* (string) data value
      Output: None
      */
      void putValueForKey (DataItem** hashArray, int key, char *data) {
      /* Get the hash */
      int hashIndex = hashCode(key);

      DataItem *item = (DataItem*) malloc(sizeof(DataItem));
      item->data = data;
      item->key = key;

      /* Move in array until an empty or deleted cell */
      while(hashArray[hashIndex] != NULL) {
      /* Go to next cell */
      ++hashIndex;

      /* Wrap around the table */
      hashIndex %= SIZE;
      }

      hashArray[hashIndex] = item;
      }

      /*
      Deleting a DataItem node from an hash array
      Input: Pointer to hashArray array, pointer to the item we want to delete
      Output: The deleted item pointer
      */
      DataItem* deleteHash (DataItem** hashArray, DataItem* item) {
      int key;
      int hashIndex;
      if (item == NULL)
      {
      return NULL;
      }

      key = item->key;

      /* Get the hash */
      hashIndex = hashCode(key);

      /* Move in array until an empty */
      while(hashArray[hashIndex] != NULL) {

      if(hashArray[hashIndex]->key == key) {
      DataItem* temp = hashArray[hashIndex];

      /* Assign a dummy item at deleted position */
      hashArray[hashIndex] = NULL;
      return temp;
      }

      /* Go to next cell */
      ++hashIndex;

      /* Wrap around the table */
      hashIndex %= SIZE;
      }

      return NULL;
      }

      /*
      displaying an hash array
      Input: Pointer to hashArray array
      Output: None
      */
      void displayHashTable (DataItem** hashArray) {
      int i = 0;

      for (i = 0; i < SIZE; i++) {

      if (hashArray[i] != NULL)
      printf(" (%d,%s)",hashArray[i]->key,hashArray[i]->data);
      else
      printf(" ~~ ");
      }

      printf("n");
      }

      /*
      Freeing an hash array
      Input: Pointer to hashArray array
      Output: None
      */
      void freeHashTable (DataItem** hashArray) {
      int i = 0;
      for (i = 0; i < SIZE; ++i)
      {
      if (hashArray[i] != NULL) {
      free(hashArray[i]);
      }
      }
      }

      /*
      Initialize an hash array by setting all the nodes to NULL
      Input: Pointer to hashArray array
      Output: None
      */
      void initializeHashArray (DataItem** hashArray) {
      int i = 0;
      for (i = 0; i < SIZE; i++) {
      hashArray[i] = NULL;
      }
      }

      int main() {
      DataItem* hashArray[SIZE];
      initializeHashArray(hashArray);

      putValueForKey(hashArray, 100, "MAIN");
      putValueForKey(hashArray, 107, "LOOP");
      putValueForKey(hashArray, 121, "END");
      putValueForKey(hashArray, 122, "STR");
      putValueForKey(hashArray, 129, "LENGTHHHHHHHHHHHHHHHHHHHHH");
      putValueForKey(hashArray, 132, "K");
      putValueForKey(hashArray, 133, "M1");


      displayHashTable(hashArray);
      DataItem* item = getValueByKey(hashArray, 100);

      if (item != NULL) {
      printf("Element found: %sn", item->data);
      }
      else {
      printf("Element not foundn");
      }

      deleteHash(hashArray, item);
      item = getValueByKey(hashArray, 100);

      if (item != NULL) {
      printf("Element found: %sn", item->data);
      }
      else {
      printf("Element not foundn");
      }
      displayHashTable(hashArray);

      freeHashTable(hashArray);
      }


      I believe this code is well commented and very understandable, if you think it's not please let me know.



      The main is there just for testing and will not be part of the final code.



      My main concerns are:




      1. The free function (freeHashTable) because I don't know how to test it so I don't know if it's working.


      2. The while loops that might get into an infinite loop condition for some reason.



      Also this is the first time I'm trying to implement hash table, so if I'm missing something from the logical aspect of hash code explanation will be very welcomed.




      hashTable.h:




      #define SIZE 20

      struct DataItem {
      char *data;
      int key;
      }typedef DataItem;

      DataItem *getValueByKey (DataItem** hashArray, int key);
      void putValueForKey (DataItem** hashArray, int key, char *data);
      DataItem* deleteHash (DataItem** hashArray, DataItem* item);
      void displayHashTable (DataItem** hashArray);
      void freeHashTable (DataItem** hashArray);
      void initializeHashArray (DataItem** hashArray);


      Thanks in advance!







      c hash-table






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Aug 1 '17 at 18:39









      Yonlif

      1546




      1546






















          4 Answers
          4






          active

          oldest

          votes

















          up vote
          0
          down vote



          accepted










          Fix the compiler warnings



          These should all be straightforward to address:



          gcc -std=c17 -fPIC -g -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds      -Wconversion    171784.c    -o 171784
          171784.c:11:1: warning: ‘typedef’ is not at beginning of declaration [-Wold-style-declaration]
          }typedef DataItem;
          ^
          171784.c: In function ‘main’:
          171784.c:163:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
          putValueForKey(hashArray, 100, "MAIN");
          ^~~~~~
          171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
          void putValueForKey(DataItem** hashArray, int key, char *data) {
          ~~~~~~^~~~
          171784.c:164:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
          putValueForKey(hashArray, 107, "LOOP");
          ^~~~~~
          171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
          void putValueForKey(DataItem** hashArray, int key, char *data) {
          ~~~~~~^~~~
          171784.c:165:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
          putValueForKey(hashArray, 121, "END");
          ^~~~~
          171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
          void putValueForKey(DataItem** hashArray, int key, char *data) {
          ~~~~~~^~~~
          171784.c:166:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
          putValueForKey(hashArray, 122, "STR");
          ^~~~~
          171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
          void putValueForKey(DataItem** hashArray, int key, char *data) {
          ~~~~~~^~~~
          171784.c:167:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
          putValueForKey(hashArray, 129, "LENGTHHHHHHHHHHHHHHHHHHHHH");
          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
          171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
          void putValueForKey(DataItem** hashArray, int key, char *data) {
          ~~~~~~^~~~
          171784.c:168:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
          putValueForKey(hashArray, 132, "K");
          ^~~
          171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
          void putValueForKey(DataItem** hashArray, int key, char *data) {
          ~~~~~~^~~~
          171784.c:169:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
          putValueForKey(hashArray, 133, "M1");
          ^~~~
          171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
          void putValueForKey(DataItem** hashArray, int key, char *data) {
          ~~~~~~^~~~


          Fix the memory leak



          valgrind -q --leak-check=full ./171784   
          (100,MAIN) (121,END) (122,STR) ~~ ~~ ~~ ~~ (107,LOOP) ~~ (129,LENGTHHHHHHHHHHHHHHHHHHHHH) ~~ ~~ (132,K) (133,M1) ~~ ~~ ~~ ~~ ~~ ~~
          Element found: MAIN
          Element not found
          ~~ (121,END) (122,STR) ~~ ~~ ~~ ~~ (107,LOOP) ~~ (129,LENGTHHHHHHHHHHHHHHHHHHHHH) ~~ ~~ (132,K) (133,M1) ~~ ~~ ~~ ~~ ~~ ~~
          ==26310== 16 bytes in 1 blocks are definitely lost in loss record 1 of 1
          ==26310== at 0x483577F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
          ==26310== by 0x109271: putValueForKey (171784.c:60)
          ==26310== by 0x10955D: main (171784.c:163)
          ==26310==


          It seems that the first item to be inserted was never freed.



          That seems to be a bug in the test program: deleteHash() transfers ownership to its caller, meaning that main() is now responsible for freeing that item. It's easily fixed:



          free(deleteHash(hashArray, item));


          However, this is a warning that you might not have thought sufficiently about ownership of objects, in general. Give this some more thought, and try to make your code easy to use correctly, and harder to use incorrectly.



          Style points



          I noticed a few things whilst looking at this, but haven't done a thorough inspection. Other reviews have addressed quite a few style points; I'll try to make only new observations here.





          • Don't cast the result of malloc() and family, and prefer to use the size of the variable rather than its type, to ensure consistency (and make that consistency obvious):



            DataItem *item =  malloc(sizeof *item);



          • It's fine to pass a null pointer to free(), so there's very little point pre-testing the argument:



            for (size_t i = 0;  i < SIZE;  ++i) {
            free(hashArray[i]);
            }



          Add more tests



          The main() function performs only a very basic test. We should add tests that




          • attempt to insert duplicate keys and entries with negative keys

          • attempt to insert more than SIZE entries

          • attempt to remove keys that aren't present


          And we might consider tests of misuse, such as




          • calling freeHashTable() twice


          Advanced testing would also substitute malloc() with a library that allows failure injection, so that we can test the error paths.






          share|improve this answer




























            up vote
            3
            down vote














            1. while loops can never terminate if the table is full. If all the slots're used and you're trying to insert a new element or look for a key that isn't there, it'll keep wrapping around as there're no NULL elements in the array.


            2. You can fix it by terminating the loop after SIZE iterations, but it's only part of the problem.


            3. The real question is: what is the desired behavior in this case? Being unable to keep more than SIZE elements (which should be known at compile time) is a serious limitation. In fact, a hash table that can hold only 20 elements is likely to be quite useless in practice (if the amount of data is so small, a simple array is unlikely to cause any performance issues). Ideally, the table should grow when there's too little room left. Roughly speaking, you should allocate a larger array, rehash the elements, but them into it, and delete old array.


            4. Even if you decide to keep it fixed-size for simplicity, you need to indicate that the table is full somehow. It shouldn't silently fail to insert a new element. Using error codes is a typical way to do it in C.


            5. You can run your program under valgrind (or some other memory-checking tool) to see if it leaks memory. If it does, your free... function's wrong (or is called improperly).


            6. Assuming that malloc always returns a valid pointer is dangerous. It may not. You need to check if its return value is not NULL before working with it.


            7. deleteHash is not a good name. It doesn't delete a hash. It deletes a key. It should be called correspondingly.


            8. It's not clear how you code behaves if the user tries to insert a key that's already in the table. Does it allow duplicates? What value does it return upon lookup in this case? Whatever the policy is, document it.







            share|improve this answer





















            • I will fix the while loop thanks! This code is just a part from a bigger project im working on and I'm allowed to decided on a max size of the hash table, but thanks any way. I didn't know these kind of programs exist, I will use them. I totally forgot about the malloc. So changing it to deleteKeyFromHashTable is good (it's pretty long) Since it's part of a bigger project I'm the user so there will be no double input. Thanks alot once again!
              – Yonlif
              Aug 1 '17 at 20:03












            • Just another small question, what should I do if I can't malloc any more?
              – Yonlif
              Aug 1 '17 at 20:11










            • @Yonlif You should fail with some error (you can return an error code from this function, check for it in the main function, write a message to the screen and exit). That's not something your program can normally recover from.
              – kraskevich
              Aug 1 '17 at 20:20


















            up vote
            2
            down vote













            Bug



            If you insert a key, it might get pushed forward in the array because other keys are in the way. Then if you delete one of those keys that were in the way, you can never retrieve the first key. For example, imagine that key A and key B hash to the same index. Then if you do this :



            putValueForKey(hash, A, data1); // Ends up in slot [0]
            putValueForKey(hash, B, data1); // Ends up in slot [1]
            deleteHash(hash, A); // Now slot [0] is NULL


            Then you can never find key B again:



            // Here, ret becomes NULL because the hash table can't find B any more!
            ret = getValueByKey(hash, B);


            In order to fix this bug, your deletion function needs to be a lot more complicated. You should read this wikipedia article on how to delete an item when using linear probing. Better yet, you could choose a different collision strategy than linear probing. Here are some alternatives.






            share|improve this answer




























              up vote
              1
              down vote














              The while loops that might get into an infinite loop condition for some reason.




              Bug: ability to generate negative hash indexes leads to UB, which includes the above concern.



              putValueForKey(hashArray, -100, "minus");


              Should key have a negative value, so will hashCode() return a negative value which causes out-of-bounds array access.



              Various ways to handle that. For me I would use an unsigned type like unsigned or size_t. Also amend calling code.



              // int hashCode(int key) {
              unsigned hashCode(int key) {
              return (unsigned) key % SIZE;
              }




              Other idea:



              Consider prime values for HASH



              Certainly hashCode() here is a simple function and not truly meant to hash the key highly uniformly across [0...SIZE). Yet remember that if the hash calculation before the final % SIZE is good, finding the remainder with any SIZE will be good too.



              On the other hand (OTOH), if the hash calculation before the % SIZE is weak, using a prime for SIZE will likely to make it better. Example



              // #define SIZE 20
              #define SIZE 23

              unsigned hashCode(int key) {
              return (unsigned) key % SIZE;
              }





              share|improve this answer























                Your Answer





                StackExchange.ifUsing("editor", function () {
                return StackExchange.using("mathjaxEditing", function () {
                StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
                StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
                });
                });
                }, "mathjax-editing");

                StackExchange.ifUsing("editor", function () {
                StackExchange.using("externalEditor", function () {
                StackExchange.using("snippets", function () {
                StackExchange.snippets.init();
                });
                });
                }, "code-snippets");

                StackExchange.ready(function() {
                var channelOptions = {
                tags: "".split(" "),
                id: "196"
                };
                initTagRenderer("".split(" "), "".split(" "), channelOptions);

                StackExchange.using("externalEditor", function() {
                // Have to fire editor after snippets, if snippets enabled
                if (StackExchange.settings.snippets.snippetsEnabled) {
                StackExchange.using("snippets", function() {
                createEditor();
                });
                }
                else {
                createEditor();
                }
                });

                function createEditor() {
                StackExchange.prepareEditor({
                heartbeatType: 'answer',
                convertImagesToLinks: false,
                noModals: true,
                showLowRepImageUploadWarning: true,
                reputationToPostImages: null,
                bindNavPrevention: true,
                postfix: "",
                imageUploader: {
                brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
                contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
                allowUrls: true
                },
                onDemand: true,
                discardSelector: ".discard-answer"
                ,immediatelyShowMarkdownHelp:true
                });


                }
                });














                draft saved

                draft discarded


















                StackExchange.ready(
                function () {
                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f171784%2fc-hashtable-implementation%23new-answer', 'question_page');
                }
                );

                Post as a guest















                Required, but never shown

























                4 Answers
                4






                active

                oldest

                votes








                4 Answers
                4






                active

                oldest

                votes









                active

                oldest

                votes






                active

                oldest

                votes








                up vote
                0
                down vote



                accepted










                Fix the compiler warnings



                These should all be straightforward to address:



                gcc -std=c17 -fPIC -g -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds      -Wconversion    171784.c    -o 171784
                171784.c:11:1: warning: ‘typedef’ is not at beginning of declaration [-Wold-style-declaration]
                }typedef DataItem;
                ^
                171784.c: In function ‘main’:
                171784.c:163:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                putValueForKey(hashArray, 100, "MAIN");
                ^~~~~~
                171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                void putValueForKey(DataItem** hashArray, int key, char *data) {
                ~~~~~~^~~~
                171784.c:164:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                putValueForKey(hashArray, 107, "LOOP");
                ^~~~~~
                171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                void putValueForKey(DataItem** hashArray, int key, char *data) {
                ~~~~~~^~~~
                171784.c:165:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                putValueForKey(hashArray, 121, "END");
                ^~~~~
                171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                void putValueForKey(DataItem** hashArray, int key, char *data) {
                ~~~~~~^~~~
                171784.c:166:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                putValueForKey(hashArray, 122, "STR");
                ^~~~~
                171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                void putValueForKey(DataItem** hashArray, int key, char *data) {
                ~~~~~~^~~~
                171784.c:167:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                putValueForKey(hashArray, 129, "LENGTHHHHHHHHHHHHHHHHHHHHH");
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
                171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                void putValueForKey(DataItem** hashArray, int key, char *data) {
                ~~~~~~^~~~
                171784.c:168:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                putValueForKey(hashArray, 132, "K");
                ^~~
                171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                void putValueForKey(DataItem** hashArray, int key, char *data) {
                ~~~~~~^~~~
                171784.c:169:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                putValueForKey(hashArray, 133, "M1");
                ^~~~
                171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                void putValueForKey(DataItem** hashArray, int key, char *data) {
                ~~~~~~^~~~


                Fix the memory leak



                valgrind -q --leak-check=full ./171784   
                (100,MAIN) (121,END) (122,STR) ~~ ~~ ~~ ~~ (107,LOOP) ~~ (129,LENGTHHHHHHHHHHHHHHHHHHHHH) ~~ ~~ (132,K) (133,M1) ~~ ~~ ~~ ~~ ~~ ~~
                Element found: MAIN
                Element not found
                ~~ (121,END) (122,STR) ~~ ~~ ~~ ~~ (107,LOOP) ~~ (129,LENGTHHHHHHHHHHHHHHHHHHHHH) ~~ ~~ (132,K) (133,M1) ~~ ~~ ~~ ~~ ~~ ~~
                ==26310== 16 bytes in 1 blocks are definitely lost in loss record 1 of 1
                ==26310== at 0x483577F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
                ==26310== by 0x109271: putValueForKey (171784.c:60)
                ==26310== by 0x10955D: main (171784.c:163)
                ==26310==


                It seems that the first item to be inserted was never freed.



                That seems to be a bug in the test program: deleteHash() transfers ownership to its caller, meaning that main() is now responsible for freeing that item. It's easily fixed:



                free(deleteHash(hashArray, item));


                However, this is a warning that you might not have thought sufficiently about ownership of objects, in general. Give this some more thought, and try to make your code easy to use correctly, and harder to use incorrectly.



                Style points



                I noticed a few things whilst looking at this, but haven't done a thorough inspection. Other reviews have addressed quite a few style points; I'll try to make only new observations here.





                • Don't cast the result of malloc() and family, and prefer to use the size of the variable rather than its type, to ensure consistency (and make that consistency obvious):



                  DataItem *item =  malloc(sizeof *item);



                • It's fine to pass a null pointer to free(), so there's very little point pre-testing the argument:



                  for (size_t i = 0;  i < SIZE;  ++i) {
                  free(hashArray[i]);
                  }



                Add more tests



                The main() function performs only a very basic test. We should add tests that




                • attempt to insert duplicate keys and entries with negative keys

                • attempt to insert more than SIZE entries

                • attempt to remove keys that aren't present


                And we might consider tests of misuse, such as




                • calling freeHashTable() twice


                Advanced testing would also substitute malloc() with a library that allows failure injection, so that we can test the error paths.






                share|improve this answer

























                  up vote
                  0
                  down vote



                  accepted










                  Fix the compiler warnings



                  These should all be straightforward to address:



                  gcc -std=c17 -fPIC -g -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds      -Wconversion    171784.c    -o 171784
                  171784.c:11:1: warning: ‘typedef’ is not at beginning of declaration [-Wold-style-declaration]
                  }typedef DataItem;
                  ^
                  171784.c: In function ‘main’:
                  171784.c:163:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                  putValueForKey(hashArray, 100, "MAIN");
                  ^~~~~~
                  171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                  void putValueForKey(DataItem** hashArray, int key, char *data) {
                  ~~~~~~^~~~
                  171784.c:164:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                  putValueForKey(hashArray, 107, "LOOP");
                  ^~~~~~
                  171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                  void putValueForKey(DataItem** hashArray, int key, char *data) {
                  ~~~~~~^~~~
                  171784.c:165:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                  putValueForKey(hashArray, 121, "END");
                  ^~~~~
                  171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                  void putValueForKey(DataItem** hashArray, int key, char *data) {
                  ~~~~~~^~~~
                  171784.c:166:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                  putValueForKey(hashArray, 122, "STR");
                  ^~~~~
                  171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                  void putValueForKey(DataItem** hashArray, int key, char *data) {
                  ~~~~~~^~~~
                  171784.c:167:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                  putValueForKey(hashArray, 129, "LENGTHHHHHHHHHHHHHHHHHHHHH");
                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
                  171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                  void putValueForKey(DataItem** hashArray, int key, char *data) {
                  ~~~~~~^~~~
                  171784.c:168:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                  putValueForKey(hashArray, 132, "K");
                  ^~~
                  171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                  void putValueForKey(DataItem** hashArray, int key, char *data) {
                  ~~~~~~^~~~
                  171784.c:169:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                  putValueForKey(hashArray, 133, "M1");
                  ^~~~
                  171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                  void putValueForKey(DataItem** hashArray, int key, char *data) {
                  ~~~~~~^~~~


                  Fix the memory leak



                  valgrind -q --leak-check=full ./171784   
                  (100,MAIN) (121,END) (122,STR) ~~ ~~ ~~ ~~ (107,LOOP) ~~ (129,LENGTHHHHHHHHHHHHHHHHHHHHH) ~~ ~~ (132,K) (133,M1) ~~ ~~ ~~ ~~ ~~ ~~
                  Element found: MAIN
                  Element not found
                  ~~ (121,END) (122,STR) ~~ ~~ ~~ ~~ (107,LOOP) ~~ (129,LENGTHHHHHHHHHHHHHHHHHHHHH) ~~ ~~ (132,K) (133,M1) ~~ ~~ ~~ ~~ ~~ ~~
                  ==26310== 16 bytes in 1 blocks are definitely lost in loss record 1 of 1
                  ==26310== at 0x483577F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
                  ==26310== by 0x109271: putValueForKey (171784.c:60)
                  ==26310== by 0x10955D: main (171784.c:163)
                  ==26310==


                  It seems that the first item to be inserted was never freed.



                  That seems to be a bug in the test program: deleteHash() transfers ownership to its caller, meaning that main() is now responsible for freeing that item. It's easily fixed:



                  free(deleteHash(hashArray, item));


                  However, this is a warning that you might not have thought sufficiently about ownership of objects, in general. Give this some more thought, and try to make your code easy to use correctly, and harder to use incorrectly.



                  Style points



                  I noticed a few things whilst looking at this, but haven't done a thorough inspection. Other reviews have addressed quite a few style points; I'll try to make only new observations here.





                  • Don't cast the result of malloc() and family, and prefer to use the size of the variable rather than its type, to ensure consistency (and make that consistency obvious):



                    DataItem *item =  malloc(sizeof *item);



                  • It's fine to pass a null pointer to free(), so there's very little point pre-testing the argument:



                    for (size_t i = 0;  i < SIZE;  ++i) {
                    free(hashArray[i]);
                    }



                  Add more tests



                  The main() function performs only a very basic test. We should add tests that




                  • attempt to insert duplicate keys and entries with negative keys

                  • attempt to insert more than SIZE entries

                  • attempt to remove keys that aren't present


                  And we might consider tests of misuse, such as




                  • calling freeHashTable() twice


                  Advanced testing would also substitute malloc() with a library that allows failure injection, so that we can test the error paths.






                  share|improve this answer























                    up vote
                    0
                    down vote



                    accepted







                    up vote
                    0
                    down vote



                    accepted






                    Fix the compiler warnings



                    These should all be straightforward to address:



                    gcc -std=c17 -fPIC -g -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds      -Wconversion    171784.c    -o 171784
                    171784.c:11:1: warning: ‘typedef’ is not at beginning of declaration [-Wold-style-declaration]
                    }typedef DataItem;
                    ^
                    171784.c: In function ‘main’:
                    171784.c:163:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                    putValueForKey(hashArray, 100, "MAIN");
                    ^~~~~~
                    171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                    void putValueForKey(DataItem** hashArray, int key, char *data) {
                    ~~~~~~^~~~
                    171784.c:164:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                    putValueForKey(hashArray, 107, "LOOP");
                    ^~~~~~
                    171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                    void putValueForKey(DataItem** hashArray, int key, char *data) {
                    ~~~~~~^~~~
                    171784.c:165:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                    putValueForKey(hashArray, 121, "END");
                    ^~~~~
                    171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                    void putValueForKey(DataItem** hashArray, int key, char *data) {
                    ~~~~~~^~~~
                    171784.c:166:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                    putValueForKey(hashArray, 122, "STR");
                    ^~~~~
                    171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                    void putValueForKey(DataItem** hashArray, int key, char *data) {
                    ~~~~~~^~~~
                    171784.c:167:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                    putValueForKey(hashArray, 129, "LENGTHHHHHHHHHHHHHHHHHHHHH");
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
                    171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                    void putValueForKey(DataItem** hashArray, int key, char *data) {
                    ~~~~~~^~~~
                    171784.c:168:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                    putValueForKey(hashArray, 132, "K");
                    ^~~
                    171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                    void putValueForKey(DataItem** hashArray, int key, char *data) {
                    ~~~~~~^~~~
                    171784.c:169:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                    putValueForKey(hashArray, 133, "M1");
                    ^~~~
                    171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                    void putValueForKey(DataItem** hashArray, int key, char *data) {
                    ~~~~~~^~~~


                    Fix the memory leak



                    valgrind -q --leak-check=full ./171784   
                    (100,MAIN) (121,END) (122,STR) ~~ ~~ ~~ ~~ (107,LOOP) ~~ (129,LENGTHHHHHHHHHHHHHHHHHHHHH) ~~ ~~ (132,K) (133,M1) ~~ ~~ ~~ ~~ ~~ ~~
                    Element found: MAIN
                    Element not found
                    ~~ (121,END) (122,STR) ~~ ~~ ~~ ~~ (107,LOOP) ~~ (129,LENGTHHHHHHHHHHHHHHHHHHHHH) ~~ ~~ (132,K) (133,M1) ~~ ~~ ~~ ~~ ~~ ~~
                    ==26310== 16 bytes in 1 blocks are definitely lost in loss record 1 of 1
                    ==26310== at 0x483577F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
                    ==26310== by 0x109271: putValueForKey (171784.c:60)
                    ==26310== by 0x10955D: main (171784.c:163)
                    ==26310==


                    It seems that the first item to be inserted was never freed.



                    That seems to be a bug in the test program: deleteHash() transfers ownership to its caller, meaning that main() is now responsible for freeing that item. It's easily fixed:



                    free(deleteHash(hashArray, item));


                    However, this is a warning that you might not have thought sufficiently about ownership of objects, in general. Give this some more thought, and try to make your code easy to use correctly, and harder to use incorrectly.



                    Style points



                    I noticed a few things whilst looking at this, but haven't done a thorough inspection. Other reviews have addressed quite a few style points; I'll try to make only new observations here.





                    • Don't cast the result of malloc() and family, and prefer to use the size of the variable rather than its type, to ensure consistency (and make that consistency obvious):



                      DataItem *item =  malloc(sizeof *item);



                    • It's fine to pass a null pointer to free(), so there's very little point pre-testing the argument:



                      for (size_t i = 0;  i < SIZE;  ++i) {
                      free(hashArray[i]);
                      }



                    Add more tests



                    The main() function performs only a very basic test. We should add tests that




                    • attempt to insert duplicate keys and entries with negative keys

                    • attempt to insert more than SIZE entries

                    • attempt to remove keys that aren't present


                    And we might consider tests of misuse, such as




                    • calling freeHashTable() twice


                    Advanced testing would also substitute malloc() with a library that allows failure injection, so that we can test the error paths.






                    share|improve this answer












                    Fix the compiler warnings



                    These should all be straightforward to address:



                    gcc -std=c17 -fPIC -g -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds      -Wconversion    171784.c    -o 171784
                    171784.c:11:1: warning: ‘typedef’ is not at beginning of declaration [-Wold-style-declaration]
                    }typedef DataItem;
                    ^
                    171784.c: In function ‘main’:
                    171784.c:163:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                    putValueForKey(hashArray, 100, "MAIN");
                    ^~~~~~
                    171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                    void putValueForKey(DataItem** hashArray, int key, char *data) {
                    ~~~~~~^~~~
                    171784.c:164:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                    putValueForKey(hashArray, 107, "LOOP");
                    ^~~~~~
                    171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                    void putValueForKey(DataItem** hashArray, int key, char *data) {
                    ~~~~~~^~~~
                    171784.c:165:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                    putValueForKey(hashArray, 121, "END");
                    ^~~~~
                    171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                    void putValueForKey(DataItem** hashArray, int key, char *data) {
                    ~~~~~~^~~~
                    171784.c:166:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                    putValueForKey(hashArray, 122, "STR");
                    ^~~~~
                    171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                    void putValueForKey(DataItem** hashArray, int key, char *data) {
                    ~~~~~~^~~~
                    171784.c:167:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                    putValueForKey(hashArray, 129, "LENGTHHHHHHHHHHHHHHHHHHHHH");
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
                    171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                    void putValueForKey(DataItem** hashArray, int key, char *data) {
                    ~~~~~~^~~~
                    171784.c:168:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                    putValueForKey(hashArray, 132, "K");
                    ^~~
                    171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                    void putValueForKey(DataItem** hashArray, int key, char *data) {
                    ~~~~~~^~~~
                    171784.c:169:36: warning: passing argument 3 of ‘putValueForKey’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                    putValueForKey(hashArray, 133, "M1");
                    ^~~~
                    171784.c:56:58: note: expected ‘char *’ but argument is of type ‘const char *’
                    void putValueForKey(DataItem** hashArray, int key, char *data) {
                    ~~~~~~^~~~


                    Fix the memory leak



                    valgrind -q --leak-check=full ./171784   
                    (100,MAIN) (121,END) (122,STR) ~~ ~~ ~~ ~~ (107,LOOP) ~~ (129,LENGTHHHHHHHHHHHHHHHHHHHHH) ~~ ~~ (132,K) (133,M1) ~~ ~~ ~~ ~~ ~~ ~~
                    Element found: MAIN
                    Element not found
                    ~~ (121,END) (122,STR) ~~ ~~ ~~ ~~ (107,LOOP) ~~ (129,LENGTHHHHHHHHHHHHHHHHHHHHH) ~~ ~~ (132,K) (133,M1) ~~ ~~ ~~ ~~ ~~ ~~
                    ==26310== 16 bytes in 1 blocks are definitely lost in loss record 1 of 1
                    ==26310== at 0x483577F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
                    ==26310== by 0x109271: putValueForKey (171784.c:60)
                    ==26310== by 0x10955D: main (171784.c:163)
                    ==26310==


                    It seems that the first item to be inserted was never freed.



                    That seems to be a bug in the test program: deleteHash() transfers ownership to its caller, meaning that main() is now responsible for freeing that item. It's easily fixed:



                    free(deleteHash(hashArray, item));


                    However, this is a warning that you might not have thought sufficiently about ownership of objects, in general. Give this some more thought, and try to make your code easy to use correctly, and harder to use incorrectly.



                    Style points



                    I noticed a few things whilst looking at this, but haven't done a thorough inspection. Other reviews have addressed quite a few style points; I'll try to make only new observations here.





                    • Don't cast the result of malloc() and family, and prefer to use the size of the variable rather than its type, to ensure consistency (and make that consistency obvious):



                      DataItem *item =  malloc(sizeof *item);



                    • It's fine to pass a null pointer to free(), so there's very little point pre-testing the argument:



                      for (size_t i = 0;  i < SIZE;  ++i) {
                      free(hashArray[i]);
                      }



                    Add more tests



                    The main() function performs only a very basic test. We should add tests that




                    • attempt to insert duplicate keys and entries with negative keys

                    • attempt to insert more than SIZE entries

                    • attempt to remove keys that aren't present


                    And we might consider tests of misuse, such as




                    • calling freeHashTable() twice


                    Advanced testing would also substitute malloc() with a library that allows failure injection, so that we can test the error paths.







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Dec 6 at 10:43









                    Toby Speight

                    23.2k638110




                    23.2k638110
























                        up vote
                        3
                        down vote














                        1. while loops can never terminate if the table is full. If all the slots're used and you're trying to insert a new element or look for a key that isn't there, it'll keep wrapping around as there're no NULL elements in the array.


                        2. You can fix it by terminating the loop after SIZE iterations, but it's only part of the problem.


                        3. The real question is: what is the desired behavior in this case? Being unable to keep more than SIZE elements (which should be known at compile time) is a serious limitation. In fact, a hash table that can hold only 20 elements is likely to be quite useless in practice (if the amount of data is so small, a simple array is unlikely to cause any performance issues). Ideally, the table should grow when there's too little room left. Roughly speaking, you should allocate a larger array, rehash the elements, but them into it, and delete old array.


                        4. Even if you decide to keep it fixed-size for simplicity, you need to indicate that the table is full somehow. It shouldn't silently fail to insert a new element. Using error codes is a typical way to do it in C.


                        5. You can run your program under valgrind (or some other memory-checking tool) to see if it leaks memory. If it does, your free... function's wrong (or is called improperly).


                        6. Assuming that malloc always returns a valid pointer is dangerous. It may not. You need to check if its return value is not NULL before working with it.


                        7. deleteHash is not a good name. It doesn't delete a hash. It deletes a key. It should be called correspondingly.


                        8. It's not clear how you code behaves if the user tries to insert a key that's already in the table. Does it allow duplicates? What value does it return upon lookup in this case? Whatever the policy is, document it.







                        share|improve this answer





















                        • I will fix the while loop thanks! This code is just a part from a bigger project im working on and I'm allowed to decided on a max size of the hash table, but thanks any way. I didn't know these kind of programs exist, I will use them. I totally forgot about the malloc. So changing it to deleteKeyFromHashTable is good (it's pretty long) Since it's part of a bigger project I'm the user so there will be no double input. Thanks alot once again!
                          – Yonlif
                          Aug 1 '17 at 20:03












                        • Just another small question, what should I do if I can't malloc any more?
                          – Yonlif
                          Aug 1 '17 at 20:11










                        • @Yonlif You should fail with some error (you can return an error code from this function, check for it in the main function, write a message to the screen and exit). That's not something your program can normally recover from.
                          – kraskevich
                          Aug 1 '17 at 20:20















                        up vote
                        3
                        down vote














                        1. while loops can never terminate if the table is full. If all the slots're used and you're trying to insert a new element or look for a key that isn't there, it'll keep wrapping around as there're no NULL elements in the array.


                        2. You can fix it by terminating the loop after SIZE iterations, but it's only part of the problem.


                        3. The real question is: what is the desired behavior in this case? Being unable to keep more than SIZE elements (which should be known at compile time) is a serious limitation. In fact, a hash table that can hold only 20 elements is likely to be quite useless in practice (if the amount of data is so small, a simple array is unlikely to cause any performance issues). Ideally, the table should grow when there's too little room left. Roughly speaking, you should allocate a larger array, rehash the elements, but them into it, and delete old array.


                        4. Even if you decide to keep it fixed-size for simplicity, you need to indicate that the table is full somehow. It shouldn't silently fail to insert a new element. Using error codes is a typical way to do it in C.


                        5. You can run your program under valgrind (or some other memory-checking tool) to see if it leaks memory. If it does, your free... function's wrong (or is called improperly).


                        6. Assuming that malloc always returns a valid pointer is dangerous. It may not. You need to check if its return value is not NULL before working with it.


                        7. deleteHash is not a good name. It doesn't delete a hash. It deletes a key. It should be called correspondingly.


                        8. It's not clear how you code behaves if the user tries to insert a key that's already in the table. Does it allow duplicates? What value does it return upon lookup in this case? Whatever the policy is, document it.







                        share|improve this answer





















                        • I will fix the while loop thanks! This code is just a part from a bigger project im working on and I'm allowed to decided on a max size of the hash table, but thanks any way. I didn't know these kind of programs exist, I will use them. I totally forgot about the malloc. So changing it to deleteKeyFromHashTable is good (it's pretty long) Since it's part of a bigger project I'm the user so there will be no double input. Thanks alot once again!
                          – Yonlif
                          Aug 1 '17 at 20:03












                        • Just another small question, what should I do if I can't malloc any more?
                          – Yonlif
                          Aug 1 '17 at 20:11










                        • @Yonlif You should fail with some error (you can return an error code from this function, check for it in the main function, write a message to the screen and exit). That's not something your program can normally recover from.
                          – kraskevich
                          Aug 1 '17 at 20:20













                        up vote
                        3
                        down vote










                        up vote
                        3
                        down vote










                        1. while loops can never terminate if the table is full. If all the slots're used and you're trying to insert a new element or look for a key that isn't there, it'll keep wrapping around as there're no NULL elements in the array.


                        2. You can fix it by terminating the loop after SIZE iterations, but it's only part of the problem.


                        3. The real question is: what is the desired behavior in this case? Being unable to keep more than SIZE elements (which should be known at compile time) is a serious limitation. In fact, a hash table that can hold only 20 elements is likely to be quite useless in practice (if the amount of data is so small, a simple array is unlikely to cause any performance issues). Ideally, the table should grow when there's too little room left. Roughly speaking, you should allocate a larger array, rehash the elements, but them into it, and delete old array.


                        4. Even if you decide to keep it fixed-size for simplicity, you need to indicate that the table is full somehow. It shouldn't silently fail to insert a new element. Using error codes is a typical way to do it in C.


                        5. You can run your program under valgrind (or some other memory-checking tool) to see if it leaks memory. If it does, your free... function's wrong (or is called improperly).


                        6. Assuming that malloc always returns a valid pointer is dangerous. It may not. You need to check if its return value is not NULL before working with it.


                        7. deleteHash is not a good name. It doesn't delete a hash. It deletes a key. It should be called correspondingly.


                        8. It's not clear how you code behaves if the user tries to insert a key that's already in the table. Does it allow duplicates? What value does it return upon lookup in this case? Whatever the policy is, document it.







                        share|improve this answer













                        1. while loops can never terminate if the table is full. If all the slots're used and you're trying to insert a new element or look for a key that isn't there, it'll keep wrapping around as there're no NULL elements in the array.


                        2. You can fix it by terminating the loop after SIZE iterations, but it's only part of the problem.


                        3. The real question is: what is the desired behavior in this case? Being unable to keep more than SIZE elements (which should be known at compile time) is a serious limitation. In fact, a hash table that can hold only 20 elements is likely to be quite useless in practice (if the amount of data is so small, a simple array is unlikely to cause any performance issues). Ideally, the table should grow when there's too little room left. Roughly speaking, you should allocate a larger array, rehash the elements, but them into it, and delete old array.


                        4. Even if you decide to keep it fixed-size for simplicity, you need to indicate that the table is full somehow. It shouldn't silently fail to insert a new element. Using error codes is a typical way to do it in C.


                        5. You can run your program under valgrind (or some other memory-checking tool) to see if it leaks memory. If it does, your free... function's wrong (or is called improperly).


                        6. Assuming that malloc always returns a valid pointer is dangerous. It may not. You need to check if its return value is not NULL before working with it.


                        7. deleteHash is not a good name. It doesn't delete a hash. It deletes a key. It should be called correspondingly.


                        8. It's not clear how you code behaves if the user tries to insert a key that's already in the table. Does it allow duplicates? What value does it return upon lookup in this case? Whatever the policy is, document it.








                        share|improve this answer












                        share|improve this answer



                        share|improve this answer










                        answered Aug 1 '17 at 19:52









                        kraskevich

                        5,325918




                        5,325918












                        • I will fix the while loop thanks! This code is just a part from a bigger project im working on and I'm allowed to decided on a max size of the hash table, but thanks any way. I didn't know these kind of programs exist, I will use them. I totally forgot about the malloc. So changing it to deleteKeyFromHashTable is good (it's pretty long) Since it's part of a bigger project I'm the user so there will be no double input. Thanks alot once again!
                          – Yonlif
                          Aug 1 '17 at 20:03












                        • Just another small question, what should I do if I can't malloc any more?
                          – Yonlif
                          Aug 1 '17 at 20:11










                        • @Yonlif You should fail with some error (you can return an error code from this function, check for it in the main function, write a message to the screen and exit). That's not something your program can normally recover from.
                          – kraskevich
                          Aug 1 '17 at 20:20


















                        • I will fix the while loop thanks! This code is just a part from a bigger project im working on and I'm allowed to decided on a max size of the hash table, but thanks any way. I didn't know these kind of programs exist, I will use them. I totally forgot about the malloc. So changing it to deleteKeyFromHashTable is good (it's pretty long) Since it's part of a bigger project I'm the user so there will be no double input. Thanks alot once again!
                          – Yonlif
                          Aug 1 '17 at 20:03












                        • Just another small question, what should I do if I can't malloc any more?
                          – Yonlif
                          Aug 1 '17 at 20:11










                        • @Yonlif You should fail with some error (you can return an error code from this function, check for it in the main function, write a message to the screen and exit). That's not something your program can normally recover from.
                          – kraskevich
                          Aug 1 '17 at 20:20
















                        I will fix the while loop thanks! This code is just a part from a bigger project im working on and I'm allowed to decided on a max size of the hash table, but thanks any way. I didn't know these kind of programs exist, I will use them. I totally forgot about the malloc. So changing it to deleteKeyFromHashTable is good (it's pretty long) Since it's part of a bigger project I'm the user so there will be no double input. Thanks alot once again!
                        – Yonlif
                        Aug 1 '17 at 20:03






                        I will fix the while loop thanks! This code is just a part from a bigger project im working on and I'm allowed to decided on a max size of the hash table, but thanks any way. I didn't know these kind of programs exist, I will use them. I totally forgot about the malloc. So changing it to deleteKeyFromHashTable is good (it's pretty long) Since it's part of a bigger project I'm the user so there will be no double input. Thanks alot once again!
                        – Yonlif
                        Aug 1 '17 at 20:03














                        Just another small question, what should I do if I can't malloc any more?
                        – Yonlif
                        Aug 1 '17 at 20:11




                        Just another small question, what should I do if I can't malloc any more?
                        – Yonlif
                        Aug 1 '17 at 20:11












                        @Yonlif You should fail with some error (you can return an error code from this function, check for it in the main function, write a message to the screen and exit). That's not something your program can normally recover from.
                        – kraskevich
                        Aug 1 '17 at 20:20




                        @Yonlif You should fail with some error (you can return an error code from this function, check for it in the main function, write a message to the screen and exit). That's not something your program can normally recover from.
                        – kraskevich
                        Aug 1 '17 at 20:20










                        up vote
                        2
                        down vote













                        Bug



                        If you insert a key, it might get pushed forward in the array because other keys are in the way. Then if you delete one of those keys that were in the way, you can never retrieve the first key. For example, imagine that key A and key B hash to the same index. Then if you do this :



                        putValueForKey(hash, A, data1); // Ends up in slot [0]
                        putValueForKey(hash, B, data1); // Ends up in slot [1]
                        deleteHash(hash, A); // Now slot [0] is NULL


                        Then you can never find key B again:



                        // Here, ret becomes NULL because the hash table can't find B any more!
                        ret = getValueByKey(hash, B);


                        In order to fix this bug, your deletion function needs to be a lot more complicated. You should read this wikipedia article on how to delete an item when using linear probing. Better yet, you could choose a different collision strategy than linear probing. Here are some alternatives.






                        share|improve this answer

























                          up vote
                          2
                          down vote













                          Bug



                          If you insert a key, it might get pushed forward in the array because other keys are in the way. Then if you delete one of those keys that were in the way, you can never retrieve the first key. For example, imagine that key A and key B hash to the same index. Then if you do this :



                          putValueForKey(hash, A, data1); // Ends up in slot [0]
                          putValueForKey(hash, B, data1); // Ends up in slot [1]
                          deleteHash(hash, A); // Now slot [0] is NULL


                          Then you can never find key B again:



                          // Here, ret becomes NULL because the hash table can't find B any more!
                          ret = getValueByKey(hash, B);


                          In order to fix this bug, your deletion function needs to be a lot more complicated. You should read this wikipedia article on how to delete an item when using linear probing. Better yet, you could choose a different collision strategy than linear probing. Here are some alternatives.






                          share|improve this answer























                            up vote
                            2
                            down vote










                            up vote
                            2
                            down vote









                            Bug



                            If you insert a key, it might get pushed forward in the array because other keys are in the way. Then if you delete one of those keys that were in the way, you can never retrieve the first key. For example, imagine that key A and key B hash to the same index. Then if you do this :



                            putValueForKey(hash, A, data1); // Ends up in slot [0]
                            putValueForKey(hash, B, data1); // Ends up in slot [1]
                            deleteHash(hash, A); // Now slot [0] is NULL


                            Then you can never find key B again:



                            // Here, ret becomes NULL because the hash table can't find B any more!
                            ret = getValueByKey(hash, B);


                            In order to fix this bug, your deletion function needs to be a lot more complicated. You should read this wikipedia article on how to delete an item when using linear probing. Better yet, you could choose a different collision strategy than linear probing. Here are some alternatives.






                            share|improve this answer












                            Bug



                            If you insert a key, it might get pushed forward in the array because other keys are in the way. Then if you delete one of those keys that were in the way, you can never retrieve the first key. For example, imagine that key A and key B hash to the same index. Then if you do this :



                            putValueForKey(hash, A, data1); // Ends up in slot [0]
                            putValueForKey(hash, B, data1); // Ends up in slot [1]
                            deleteHash(hash, A); // Now slot [0] is NULL


                            Then you can never find key B again:



                            // Here, ret becomes NULL because the hash table can't find B any more!
                            ret = getValueByKey(hash, B);


                            In order to fix this bug, your deletion function needs to be a lot more complicated. You should read this wikipedia article on how to delete an item when using linear probing. Better yet, you could choose a different collision strategy than linear probing. Here are some alternatives.







                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Aug 1 '17 at 23:20









                            JS1

                            27.2k32976




                            27.2k32976






















                                up vote
                                1
                                down vote














                                The while loops that might get into an infinite loop condition for some reason.




                                Bug: ability to generate negative hash indexes leads to UB, which includes the above concern.



                                putValueForKey(hashArray, -100, "minus");


                                Should key have a negative value, so will hashCode() return a negative value which causes out-of-bounds array access.



                                Various ways to handle that. For me I would use an unsigned type like unsigned or size_t. Also amend calling code.



                                // int hashCode(int key) {
                                unsigned hashCode(int key) {
                                return (unsigned) key % SIZE;
                                }




                                Other idea:



                                Consider prime values for HASH



                                Certainly hashCode() here is a simple function and not truly meant to hash the key highly uniformly across [0...SIZE). Yet remember that if the hash calculation before the final % SIZE is good, finding the remainder with any SIZE will be good too.



                                On the other hand (OTOH), if the hash calculation before the % SIZE is weak, using a prime for SIZE will likely to make it better. Example



                                // #define SIZE 20
                                #define SIZE 23

                                unsigned hashCode(int key) {
                                return (unsigned) key % SIZE;
                                }





                                share|improve this answer



























                                  up vote
                                  1
                                  down vote














                                  The while loops that might get into an infinite loop condition for some reason.




                                  Bug: ability to generate negative hash indexes leads to UB, which includes the above concern.



                                  putValueForKey(hashArray, -100, "minus");


                                  Should key have a negative value, so will hashCode() return a negative value which causes out-of-bounds array access.



                                  Various ways to handle that. For me I would use an unsigned type like unsigned or size_t. Also amend calling code.



                                  // int hashCode(int key) {
                                  unsigned hashCode(int key) {
                                  return (unsigned) key % SIZE;
                                  }




                                  Other idea:



                                  Consider prime values for HASH



                                  Certainly hashCode() here is a simple function and not truly meant to hash the key highly uniformly across [0...SIZE). Yet remember that if the hash calculation before the final % SIZE is good, finding the remainder with any SIZE will be good too.



                                  On the other hand (OTOH), if the hash calculation before the % SIZE is weak, using a prime for SIZE will likely to make it better. Example



                                  // #define SIZE 20
                                  #define SIZE 23

                                  unsigned hashCode(int key) {
                                  return (unsigned) key % SIZE;
                                  }





                                  share|improve this answer

























                                    up vote
                                    1
                                    down vote










                                    up vote
                                    1
                                    down vote










                                    The while loops that might get into an infinite loop condition for some reason.




                                    Bug: ability to generate negative hash indexes leads to UB, which includes the above concern.



                                    putValueForKey(hashArray, -100, "minus");


                                    Should key have a negative value, so will hashCode() return a negative value which causes out-of-bounds array access.



                                    Various ways to handle that. For me I would use an unsigned type like unsigned or size_t. Also amend calling code.



                                    // int hashCode(int key) {
                                    unsigned hashCode(int key) {
                                    return (unsigned) key % SIZE;
                                    }




                                    Other idea:



                                    Consider prime values for HASH



                                    Certainly hashCode() here is a simple function and not truly meant to hash the key highly uniformly across [0...SIZE). Yet remember that if the hash calculation before the final % SIZE is good, finding the remainder with any SIZE will be good too.



                                    On the other hand (OTOH), if the hash calculation before the % SIZE is weak, using a prime for SIZE will likely to make it better. Example



                                    // #define SIZE 20
                                    #define SIZE 23

                                    unsigned hashCode(int key) {
                                    return (unsigned) key % SIZE;
                                    }





                                    share|improve this answer















                                    The while loops that might get into an infinite loop condition for some reason.




                                    Bug: ability to generate negative hash indexes leads to UB, which includes the above concern.



                                    putValueForKey(hashArray, -100, "minus");


                                    Should key have a negative value, so will hashCode() return a negative value which causes out-of-bounds array access.



                                    Various ways to handle that. For me I would use an unsigned type like unsigned or size_t. Also amend calling code.



                                    // int hashCode(int key) {
                                    unsigned hashCode(int key) {
                                    return (unsigned) key % SIZE;
                                    }




                                    Other idea:



                                    Consider prime values for HASH



                                    Certainly hashCode() here is a simple function and not truly meant to hash the key highly uniformly across [0...SIZE). Yet remember that if the hash calculation before the final % SIZE is good, finding the remainder with any SIZE will be good too.



                                    On the other hand (OTOH), if the hash calculation before the % SIZE is weak, using a prime for SIZE will likely to make it better. Example



                                    // #define SIZE 20
                                    #define SIZE 23

                                    unsigned hashCode(int key) {
                                    return (unsigned) key % SIZE;
                                    }






                                    share|improve this answer














                                    share|improve this answer



                                    share|improve this answer








                                    edited Aug 4 '17 at 17:22

























                                    answered Aug 4 '17 at 17:17









                                    chux

                                    12.5k11344




                                    12.5k11344






























                                        draft saved

                                        draft discarded




















































                                        Thanks for contributing an answer to Code Review Stack Exchange!


                                        • Please be sure to answer the question. Provide details and share your research!

                                        But avoid



                                        • Asking for help, clarification, or responding to other answers.

                                        • Making statements based on opinion; back them up with references or personal experience.


                                        Use MathJax to format equations. MathJax reference.


                                        To learn more, see our tips on writing great answers.





                                        Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                                        Please pay close attention to the following guidance:


                                        • Please be sure to answer the question. Provide details and share your research!

                                        But avoid



                                        • Asking for help, clarification, or responding to other answers.

                                        • Making statements based on opinion; back them up with references or personal experience.


                                        To learn more, see our tips on writing great answers.




                                        draft saved


                                        draft discarded














                                        StackExchange.ready(
                                        function () {
                                        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f171784%2fc-hashtable-implementation%23new-answer', 'question_page');
                                        }
                                        );

                                        Post as a guest















                                        Required, but never shown





















































                                        Required, but never shown














                                        Required, but never shown












                                        Required, but never shown







                                        Required, but never shown

































                                        Required, but never shown














                                        Required, but never shown












                                        Required, but never shown







                                        Required, but never shown







                                        Popular posts from this blog

                                        Список кардиналов, возведённых папой римским Каликстом III

                                        Deduzione

                                        Mysql.sock missing - “Can't connect to local MySQL server through socket”