Maps in C

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

// A simple key-value pair structure
typedef struct {
    char* key;
    int value;
} KeyValue;

// A simple map structure
typedef struct {
    KeyValue* pairs;
    int size;
    int capacity;
} Map;

// Function to create a new map
Map* makeMap() {
    Map* m = malloc(sizeof(Map));
    m->pairs = NULL;
    m->size = 0;
    m->capacity = 0;
    return m;
}

// Function to set a key-value pair in the map
void setKeyValue(Map* m, const char* key, int value) {
    for (int i = 0; i < m->size; i++) {
        if (strcmp(m->pairs[i].key, key) == 0) {
            m->pairs[i].value = value;
            return;
        }
    }
    
    if (m->size == m->capacity) {
        m->capacity = m->capacity == 0 ? 1 : m->capacity * 2;
        m->pairs = realloc(m->pairs, m->capacity * sizeof(KeyValue));
    }
    
    m->pairs[m->size].key = strdup(key);
    m->pairs[m->size].value = value;
    m->size++;
}

// Function to get a value from the map
int getValue(Map* m, const char* key, int* found) {
    for (int i = 0; i < m->size; i++) {
        if (strcmp(m->pairs[i].key, key) == 0) {
            *found = 1;
            return m->pairs[i].value;
        }
    }
    *found = 0;
    return 0;
}

// Function to delete a key-value pair from the map
void deleteKeyValue(Map* m, const char* key) {
    for (int i = 0; i < m->size; i++) {
        if (strcmp(m->pairs[i].key, key) == 0) {
            free(m->pairs[i].key);
            for (int j = i; j < m->size - 1; j++) {
                m->pairs[j] = m->pairs[j + 1];
            }
            m->size--;
            return;
        }
    }
}

// Function to clear the map
void clearMap(Map* m) {
    for (int i = 0; i < m->size; i++) {
        free(m->pairs[i].key);
    }
    free(m->pairs);
    m->pairs = NULL;
    m->size = 0;
    m->capacity = 0;
}

// Function to print the map
void printMap(Map* m) {
    printf("map: {");
    for (int i = 0; i < m->size; i++) {
        printf("%s:%d", m->pairs[i].key, m->pairs[i].value);
        if (i < m->size - 1) {
            printf(" ");
        }
    }
    printf("}\n");
}

int main() {
    // Create an empty map
    Map* m = makeMap();

    // Set key/value pairs
    setKeyValue(m, "k1", 7);
    setKeyValue(m, "k2", 13);

    // Print the map
    printMap(m);

    // Get a value for a key
    int found;
    int v1 = getValue(m, "k1", &found);
    printf("v1: %d\n", v1);

    // Get a value for a non-existent key
    int v3 = getValue(m, "k3", &found);
    printf("v3: %d\n", v3);

    // Print the length of the map
    printf("len: %d\n", m->size);

    // Delete a key/value pair
    deleteKeyValue(m, "k2");
    printMap(m);

    // Clear the map
    clearMap(m);
    printMap(m);

    // Check if a key exists
    int prs = getValue(m, "k2", &found);
    printf("prs: %s\n", found ? "true" : "false");

    // Create and initialize a new map in one line
    Map* n = makeMap();
    setKeyValue(n, "foo", 1);
    setKeyValue(n, "bar", 2);
    printMap(n);

    // Clean up
    clearMap(m);
    free(m);
    clearMap(n);
    free(n);

    return 0;
}

This C code demonstrates the implementation of a simple map (associative array) data structure. Here’s an explanation of the key points:

  1. We define a KeyValue struct to represent key-value pairs and a Map struct to hold the collection of pairs.

  2. The makeMap function creates an empty map.

  3. setKeyValue adds or updates a key-value pair in the map.

  4. getValue retrieves a value for a given key, with a boolean flag to indicate if the key was found.

  5. deleteKeyValue removes a key-value pair from the map.

  6. clearMap removes all key-value pairs from the map.

  7. printMap is a utility function to display the contents of the map.

  8. In the main function, we demonstrate various operations on the map:

    • Creating an empty map
    • Setting key-value pairs
    • Retrieving values
    • Checking the length of the map
    • Deleting a key-value pair
    • Clearing the map
    • Checking for the existence of a key

Note that this implementation is a simplified version and doesn’t include some of the more advanced features of Go’s maps, such as built-in iteration or thread-safety. In a real-world C program, you might want to use a more sophisticated hash table implementation for better performance and additional features.

To compile and run this program:

$ gcc -o maps maps.c
$ ./maps
map: {k1:7 k2:13}
v1: 7
v3: 0
len: 2
map: {k1:7}
map: {}
prs: false
map: {foo:1 bar:2}

This output demonstrates the various operations performed on the map, similar to the Go example.