Create your own associative array in C or use a library
There is no associative array library in C language, so you can either create your own or use the library.
The reason why there is no frequently used library called associative array is that there is a policy that libraries that require memory allocation inside the library are not included in the core of C language.
There are no dependencies, so you can copy and paste the header and source.
Implementation example of associative array in C language
There is no explanation, but since it is only a basic function of creating an associative array and getting and setting the value of an associative array, you can see how to use it by looking at the header. The value of the associative array is general-purpose pointer type void *. Unfortunately, the element deletion and existence verification functions are not implemented. The hash function used internally is very simple and has no security strength.
spvm_hash.h
The header of the associative array.
#ifndef SPVM_HASH_H #define SPVM_HASH_H #include <stdint.h> #include <stddef.h> struct spvm_hash; typedef struct spvm_hash SPVM_HASH; struct spvm_hash_entry; typedef struct spvm_hash_entry SPVM_HASH_ENTRY; // Hash table struct spvm_hash { int32_t * table; char * key_buffer; SPVM_HASH_ENTRY * entries; int32_t table_capacity; int32_t entries_capacity; int32_t entries_length; int32_t key_buffer_capacity; int32_t key_buffer_length; };; // Hash entry struct spvm_hash_entry { void * value; int32_t next_index; int32_t key_index; };; SPVM_HASH * SPVM_HASH_new (int32_t capacity); void SPVM_HASH_insert (SPVM_HASH * hash, const char * key, int32_t length, void * value); void * SPVM_HASH_fetch (SPVM_HASH * hash, const char * key, int32_t length); void SPVM_HASH_free (SPVM_HASH * hash); int32_t SPVM_HASH_new_hash_entry (SPVM_HASH * hash, const char * key, int32_t length, void * value); void SPVM_HASH_rehash (SPVM_HASH * hash, int32_t new_table_capacity); void SPVM_HASH_insert_norehash (SPVM_HASH * hash, const char * key, int32_t length, void * value); int32_t SPVM_HASH_calc_hash_value (const char * str, int32_t len); void SPVM_HASH_maybe_extend_entries (SPVM_HASH * hash); #endif
spvm_hash.c
An implementation of an associative array.
#include <string.h> #include <stdlib.h> #include <assert.h> #include "spvm_hash.h" SPVM_HASH * SPVM_HASH_new (int32_t table_capacity) { assert (table_capacity> = 0); // Create hash SPVM_HASH * hash = calloc (1, sizeof (SPVM_HASH)); // Default table capacity if (table_capacity == 0) { hash->table_capacity= 1; } else { hash->table_capacity= table_capacity; } // Initialize table hash->table= calloc (hash->table_capacity, sizeof (int32_t)); memset (hash->table, -1, hash->table_capacity* sizeof (int32_t)); // Initialize entries hash->entries_capacity= 1; hash->entries= calloc (hash->entries_capacity, sizeof (SPVM_HASH_ENTRY)); hash->entries_length= 0; // Initialize key buffer hash->key_buffer_capacity= 1; hash->key_buffer= calloc (1, hash->key_buffer_capacity); hash->key_buffer_length= 0; return hash; } void SPVM_HASH_insert (SPVM_HASH * hash, const char * key, int32_t length, void * value) { assert (hash); assert (key); assert (length> = 0); // Rehash if (hash->entries_length> hash->table_capacity* 0.75) { int32_t new_table_capacity = (hash->table_capacity* 2) + 1; SPVM_HASH_rehash (hash, new_table_capacity); } SPVM_HASH_insert_norehash (hash, key, length, value); } void * SPVM_HASH_fetch (SPVM_HASH * hash, const char * key, int32_t length) { assert (hash); assert (length> = 0); int32_t hash_value = SPVM_HASH_calc_hash_value (key, length); int32_t table_index = hash_value%hash->table_capacity; int32_t entry_index = -1; if (hash->table[table_index]! = -1) { entry_index = hash->table[table_index]; } while (1) { assert (entry_index> = -1); if (entry_index! = -1) { int32_t match = 0; int32_t key_length; memcpy (& key_length, & hash->key_buffer[hash->entries[entry_index] .key_index], sizeof (int32_t)); if (length == 0 && key_length == 0) { match = 1; } else if (key_length == length && memcmp (key, & hash->key_buffer[hash->entries[entry_index] .key_index + sizeof (int32_t)], length) == 0) { match = 1; } if (match) { return hash->entries[entry_index] .value; } else { if (hash->entries[entry_index] .next_index == -1) { entry_index = -1; } else { entry_index = hash->entries[entry_index] .next_index; } } } else { return NULL; } } } void SPVM_HASH_free (SPVM_HASH * hash) { assert (hash); free (hash->table); free (hash->entries); free (hash->key_buffer); free (hash); } void SPVM_HASH_maybe_extend_entries (SPVM_HASH * hash) { assert (hash); int32_t entries_length = hash->entries_length; assert (entries_length> = 0); int32_t entries_capacity = hash->entries_capacity; if (entries_length> = entries_capacity) { int32_t new_entries_capacity = entries_capacity * 2; SPVM_HASH_ENTRY * new_entries = calloc (new_entries_capacity, sizeof (SPVM_HASH_ENTRY)); memcpy (new_entries, hash->entries, entries_capacity * sizeof (SPVM_HASH_ENTRY)); free (hash->entries); hash->entries= new_entries; hash->entries_capacity= new_entries_capacity; } } void SPVM_HASH_maybe_extend_key_buffer (SPVM_HASH * hash, int32_t length) { assert (hash); int32_t key_buffer_length = hash->key_buffer_length; assert (key_buffer_length> = 0); int32_t key_buffer_capacity = hash->key_buffer_capacity; if (key_buffer_length + length + (int32_t) sizeof (int32_t)> = key_buffer_capacity) { int32_t new_key_buffer_capacity = (key_buffer_length + length + sizeof (int32_t)) * 2; char * new_key_buffer = calloc (1, new_key_buffer_capacity); memcpy (new_key_buffer, hash->key_buffer, key_buffer_capacity); free (hash->key_buffer); hash->key_buffer= new_key_buffer; hash->key_buffer_capacity= new_key_buffer_capacity; } } int32_t SPVM_HASH_new_hash_entry (SPVM_HASH * hash, const char * key, int32_t key_length, void * value) { assert (hash); assert (key); int32_t index = hash->entries_length; SPVM_HASH_maybe_extend_entries (hash); SPVM_HASH_maybe_extend_key_buffer (hash, key_length); hash->entries[index] .key_index = hash->key_buffer_length; // Copy key length memcpy (& hash->key_buffer[hash->key_buffer_length], & key_length, sizeof (int32_t)); // Copy key memcpy (& hash->key_buffer[hash->key_buffer_length+ sizeof (int32_t)], key, key_length); hash->key_buffer_length+ = sizeof (int32_t) + key_length; hash->entries[index] .value = value; hash->entries[index] .next_index = -1; hash->entries_length++; return index; } void SPVM_HASH_rehash (SPVM_HASH * hash, int32_t new_table_capacity) { assert (hash); assert (new_table_capacity> 0); // Create new hash SPVM_HASH * new_hash = SPVM_HASH_new (new_table_capacity); // Rehash { int32_t i; for (i = 0; i <hash->entries_length; i ++) { int32_t key_length; memcpy (& key_length, & hash->key_buffer[hash->entries[i] .key_index], sizeof (int32_t)); const char * key = & hash->key_buffer[hash->entries[i] .key_index + sizeof (int32_t)]; void * value = hash->entries[i] .value; SPVM_HASH_insert_norehash (new_hash, key, key_length, value); } } // Replace hash fields free (hash->table); free (hash->entries); free (hash->key_buffer); hash->entries_length= new_hash->entries_length; hash->table_capacity= new_hash->table_capacity; hash->entries_capacity= new_hash->entries_capacity; hash->table= new_hash->table; hash->entries= new_hash->entries; hash->key_buffer_capacity= new_hash->key_buffer_capacity; hash->key_buffer_length= new_hash->key_buffer_length; hash->key_buffer= new_hash->key_buffer; free (new_hash); } void SPVM_HASH_insert_norehash (SPVM_HASH * hash, const char * key, int32_t length, void * value) { assert (hash); assert (key); assert (length> = 0); int32_t hash_value = SPVM_HASH_calc_hash_value (key, length); int32_t table_index = hash_value%hash->table_capacity; assert (hash->table[table_index]> = -1); if (hash->table[table_index]! = -1) { int32_t entry_index = hash->table[table_index]; while (1) { int32_t match = 0; int32_t key_length; memcpy (& key_length, & hash->key_buffer[hash->entries[entry_index] .key_index], sizeof (int32_t)); if (key_length == 0 && length == 0) { match = 1; } else if (key_length == length && memcmp (key, & hash->key_buffer[hash->entries[entry_index] .key_index + sizeof (int32_t)], length) == 0) { match = 1; } if (match) { hash->entries[entry_index] .value = value; break; } else { if (hash->entries[entry_index] .next_index! = -1) { entry_index = hash->entries[entry_index] .next_index; } else { int32_t new_entry_index = SPVM_HASH_new_hash_entry (hash, key, length, value); hash->entries[entry_index] .next_index = new_entry_index; break; } } } } else { int32_t new_entry_index = SPVM_HASH_new_hash_entry (hash, key, length, value); hash->table[table_index] = new_entry_index; } } int32_t SPVM_HASH_calc_hash_value (const char * str, int32_t len) { assert (len> = 0); const char * str_tmp = str; int32_t hash = 5381; while (len--) { hash = ((hash << 5) + hash) + (uint8_t) * str_tmp ++; } if (hash <0) { hash = ~ hash; } return hash; }