Segmentation fault but unable to reason how, memory allocation looks fine to me

Question

I have a node and I am defining its global pointer variable as below:

typedef struct node
{
    char* word;
    struct node* next;
} node;

node* HashTable =  NULL;
node* HeadOfHashTable = NULL;

Now, I allocated memory as below:

void allocateMemory(int numOfElements, bool isRealloc, const char* word)
{
    if(!isRealloc)
    {
        printf("Allocating %d blocks\n", numOfElements);
        HashTable = malloc(sizeof(node*) * numOfElements);
    } else {
        printf("Reallocating %d blocks for %s", numOfElements, word);
        HashTable = realloc(HashTable, sizeof(node*) * numOfElements);
    }

    if(HashTable == NULL)
    {
        printf("### Out Of Memory ###\n");
        exit(0);
    }
    HeadOfHashTable = HashTable;
}

Now, I am passing a HASH value and word to put in hash table, in below method. I have commented where I am getting seg fault.

void putInHashTable(char* ch, unsigned int hashValue)
{
    HashTable  = hashValue;

    printf("Processing at address: %p and has value was %d\n", HashTable, hashValue);

    if(HashTable == NULL || HashTable == '\0' || HashTable == 0)
    {
        printf("Hash table is NULL");
    }

    if(HashTable->word == NULL)
    {
        HashTable->word = malloc(sizeof(char) * (LENGTH   1));
        strcpy(HashTable->word, ch);
        printf("New word: %s\n", HashTable->word);
    } else {
        printf("### Collision detected ###\n"); // ***** BELOW LINE GIVES SEG FAULT ******
        printf("    Earlier value is %s, new value is %s and its pointer is %p\n", HashTable->word, ch, HashTable->next);
        putInLinkedList(ch);
    }

    HashTable = HeadOfHashTable;
}

Below is console logs:

Allocating 65336 blocks
Processing at address: 0xb7568c28 and has value was 388
New word: a
Processing at address: 0xb756b9a0 and has value was 1843
New word: aaa
Processing at address: 0xb7570c08 and has value was 4480
New word: aaas
Processing at address: 0xb75ae608 and has value was 36032
### Collision detected ###
Segmentation fault (core dumped)

My doubts:

  • I am allocating 65336 blocks of memory and the point where I am getting seg fault has hash value of 36032, so I am sure that pointer variable HashTable is having a valid memory address. Then why seg fault?
  • If it is not a valid address then why it is not caught in this IF condition if(HashTable == NULL || HashTable == '\0' || HashTable == 0). I even used calloc then also I get seg fault and above IF condition is not catching.
  • I am getting seg fault at this line printf(" Earlier value is %s, new value is %s and its pointer is %p\n", HashTable->word, ch, HashTable->next);. This means some issue while de-referncing the pointer, then why I didn't get seg fault just before that, means I should have got seg fault here only - if(HashTable->word == NULL)?
Solution

Counting the stars.

 FOO * foo_ptr = malloc (sizeof (FOO) * n_foos);
 //  ^                                ^             
 //  |                                |
 //  one star to the left of `=`      one star to the right of `=`

The rule of thumb: the number of stars must be the same at either side of the assignment. Why?

      sizeof(FOO)    sizeof(FOO)    sizeof(FOO)   
     _____________  _____________  ______________
    /             \/             \/              \
     _____________  _____________  ______________
    [_____FOO_____][_____FOO_____][______FOO_____]
    ^
    |
    FOO* foo_ptr; // a FOO* points to a FOO
                  // pointer arithmetic works by incrementing the address\
                  // by sizeof(FOO)
                  // and so on

Other examples of good code:

 FOO ** foo_ptr = malloc (sizeof (FOO*) * n_foos); // same number of stars
 FOO *** foo_ptr = malloc (sizeof (FOO**) * n_foos); // still same

Bad code:

 FOO ** foo_ptr = malloc (sizeof (FOO) * n_foos); // numbers don't match
 FOO * foo_ptr = malloc (sizeof (FOO*) * n_foos); // numbers don't match

Your line

HashTable = malloc(sizeof(node*) * numOfElements);

(after substituting the type of HashTable which is node*) falls squarely into the bad code bin, so try to fix that.

If you want an array of nodes:

HashTable = malloc(sizeof(node) * numOfElements);

If you want an array of pouners to nodes, you can have that too. This is not really recommended, because space savings are small, performance degradation will probably be substantial, and the code is less elegant. But you can have it:

node** HashTable = malloc(sizeof(node*) * numOfElements); // count! the! stars!

Congratulations! You now have an array of numOfElements uninitialized pointers. Now you need to initialize them to some value, typically NULL:

for (i = 0; i < numOfElements;   i) HashTable[i] = NULL;

And you need to allocate a new node each time you want to put a value to the table:

if (HashTable[hashValue] == NULL) 
{
  HashTable[hashValue] = malloc(sizeof(node));
  if (HashTable[hashValue] == NULL) 
  {
    panic ("Out of memory!");
  }
  HashTable[hashValue]->word = ...
  HashTable[hashValue]->next = ...
} 
else 
{
  // collision etc
}

While we're at it, please note these moments which are tangential to the main question: how to properly check for NULL, how to check the return value of malloc, and how to use an array index instead of mutating a global pointer variable back and forth. (If you want to use pointer arithmetic, have a local pointer variable in putInHashTable).

(Of course if you don't use n_foos, or use calloc, you need to make mental adjustments to the number of stars).