DEV Community

Swagata Mandal
Swagata Mandal

Posted on

🧠 Building a Simple Hash Table in C (with Linear Probing)

🧠 Building a Simple Hash Table in C (with Linear Probing)

Hash tables are among the most efficient data structures when it comes to fast lookup, insert, and delete. In this article, we’ll implement a simple hash table in C — from scratch — using open addressing with linear probing.

We’ll cover:

  • Creating key-value pairs using a struct
  • A simple string hash function
  • Collision resolution with linear probing
  • Insert, search, and delete operations
  • A full working demo with explanation

🧱 Data Structure Design

We define a structure HashItem to store each key-value pair in the table.

#define TABLE_SIZE 100 
Enter fullscreen mode Exit fullscreen mode
typedef struct { char* key; int value; int isOccupied; // 0 = empty, 1 = occupied, -1 = deleted 
Enter fullscreen mode Exit fullscreen mode

} HashItem;

HashItem table[TABLE_SIZE]; // global hash table

Here:

  • key is a string (char pointer)
  • value is an integer
  • isOccupied tracks the slot status:
    • 0: empty
    • 1: occupied
    • -1: deleted (tombstone marker)

🔑 Hash Function

A basic string hash function that spreads keys reasonably well.

unsigned int hash(const char* key) { unsigned int hash = 0; while (*key) 
Enter fullscreen mode Exit fullscreen mode
 hash = (hash * 31) + *key++; // simple hash logic 
Enter fullscreen mode Exit fullscreen mode
 return hash % TABLE_SIZE; 
Enter fullscreen mode Exit fullscreen mode

}

This gives us an index between 0 and TABLE_SIZE - 1.


🔧 Insertion Logic

Handles collisions using linear probing.

void insert(const char* key, int value) { int index = hash(key); int originalIndex = index; 
Enter fullscreen mode Exit fullscreen mode
 while (table[index].isOccupied == 1 && strcmp(table[index].key, key) != 0) { 
Enter fullscreen mode Exit fullscreen mode
 index = (index + 1) % TABLE_SIZE; 
Enter fullscreen mode Exit fullscreen mode
 if (index == originalIndex) { 
Enter fullscreen mode Exit fullscreen mode
 printf("Hash table full!\n"); 
Enter fullscreen mode Exit fullscreen mode
 return; 
Enter fullscreen mode Exit fullscreen mode
 } } 
Enter fullscreen mode Exit fullscreen mode
 if (table[index].isOccupied != 1) { 
Enter fullscreen mode Exit fullscreen mode
 table[index].key = strdup(key); // copy key to heap table[index].value = value; table[index].isOccupied = 1; } else { table[index].value = value; // update if key exists } 
Enter fullscreen mode Exit fullscreen mode

}

⚠️ Notes:

  • strdup() allocates memory for the key.
  • If the key already exists, it updates the value.

🔍 Search Function

int get(const char* key) { int index = hash(key); int originalIndex = index; 
Enter fullscreen mode Exit fullscreen mode
 while (table[index].isOccupied != 0) { if (table[index].isOccupied == 1 && strcmp(table[index].key, key) == 0) return table[index].value; 
Enter fullscreen mode Exit fullscreen mode
 index = (index + 1) % TABLE_SIZE; 
Enter fullscreen mode Exit fullscreen mode
 if (index == originalIndex) break; 
Enter fullscreen mode Exit fullscreen mode
} 
Enter fullscreen mode Exit fullscreen mode
 return -1; // not found 
Enter fullscreen mode Exit fullscreen mode

}

This returns the value if found, or -1 if not present.


🗑️ Deletion

void delete(const char* key) { int index = hash(key); int originalIndex = index; 
Enter fullscreen mode Exit fullscreen mode
 while (table[index].isOccupied != 0) { if (table[index].isOccupied == 1 && strcmp(table[index].key, key) == 0) { free(table[index].key); // deallocate memory 
Enter fullscreen mode Exit fullscreen mode
 table[index].key = NULL; table[index].isOccupied = -1; printf("Deleted '%s'\n", key); 
Enter fullscreen mode Exit fullscreen mode
 return; 
Enter fullscreen mode Exit fullscreen mode
 } index = (index + 1) % TABLE_SIZE; 
Enter fullscreen mode Exit fullscreen mode
 if (index == originalIndex) break; 
Enter fullscreen mode Exit fullscreen mode
} printf("Key '%s' not found.\n", key); 
Enter fullscreen mode Exit fullscreen mode

}

We use -1 as a deleted marker so we can continue probing during future searches.


🧪 Demo

int main() { 
Enter fullscreen mode Exit fullscreen mode
insert("apple", 10); insert("banana", 20); insert("orange", 30); insert("grape", 40); printf("apple: %d\n", get("apple")); printf("banana: %d\n", get("banana")); delete("banana"); printf("banana after delete: %d\n", get("banana")); insert("banana", 50); // reinserting printf("banana new: %d\n", get("banana")); 
Enter fullscreen mode Exit fullscreen mode
 return 0; 
Enter fullscreen mode Exit fullscreen mode

}

📤 Output

apple: 10
banana: 20
Deleted 'banana'
banana after delete: -1
banana new: 50


✅ Summary

We implemented a simple fixed-size hash table in C using:

  • A basic hash function for strings
  • Linear probing for collision resolution
  • Markers for deleted slots
  • Manual memory management (malloc, strdup, free)

This is perfect for learning how hash maps work under the hood.


🚀 Bonus Ideas

  • Implement dynamic resizing (rehashing)
  • Use double hashing or quadratic probing
  • Store generic values using void*
  • Add load factor thresholds

Top comments (0)