3

I am new to C programming and I am trying to create a key value structure as in Perl Programming. I saw one solution like :-

struct key_value
{
   int key;
   char* value;
};

struct key_value kv;

kv.key = 1;
kv.value = "foo";

But I don't know how to access these values from this structure. Can someone enlight on this ?

Badda
  • 1,329
  • 2
  • 15
  • 40
Developer
  • 105
  • 1
  • 3
  • 10
  • 1
    After `struct key_value kv;`, `kv.key` and `kv.value` will be lvalues. – EOF Jun 05 '17 at 11:56
  • 1
    It's unclear what you're asking here - do you know how structs work in C? – Oliver Charlesworth Jun 05 '17 at 11:56
  • I have to store 30 key/value pair. What whould be logic to access that structure ? – Developer Jun 05 '17 at 11:57
  • 1
    You can put them into an array[30] of structs. Then with a key value, search for the struct with matching key and read/write its value. – Yunnosch Jun 05 '17 at 11:57
  • @Yunnosch Can you share a code snippet for that ? – Developer Jun 05 '17 at 11:59
  • I can, if you provide something of a [mcve] as a frame to put it in. I.e. make a little program, which has the desired key in a variable and the desired value to overwrite the key with or a variable to write the value into. Pseudo code where you wan the access to happen. – Yunnosch Jun 05 '17 at 12:00
  • As, I already told you I am new in C, I work in Perl and in perl we write it as :- my $has1={}; $hash->{r1}='val1'; $hash->{r2}='val2'; for (keys %$hash1){ print $_; } – Developer Jun 05 '17 at 12:02
  • Possible duplicate of [dictionary/map/key-value pairs data structure in C](https://stackoverflow.com/questions/4551677/dictionary-map-key-value-pairs-data-structure-in-c) – RamblinRose Jun 05 '17 at 12:06

6 Answers6

4

Here is an example:

#include <stdio.h>
#include <stdlib.h>
struct key_value
{
    int key;
    char* value;
};

int main(void)
{
    int number_of_keys = 2;
    struct key_value *kv = malloc(sizeof(struct key_value) * number_of_keys);
    if (kv == NULL) {
        perror("Malloc");
        exit(EXIT_FAILURE);
    }

    kv[0].key = 8;
    kv[0].value = "Test 8 key!";

    kv[1].key = 6;
    kv[1].value = "Test 6 key!";

    printf("Key = %d\nKey value = %s\n", kv[0].key, kv[0].value);
    printf("Key = %d\nKey value = %s\n", kv[1].key, kv[1].value);


    free(kv);
    return 0;
}
Overflow 404
  • 482
  • 5
  • 20
4

What you are missing is a collection. Most languages have a data type called a dictionary or a map or an associative array or some variation thereof. C does not have a data structure of this type; in fact, the only collection type you have built in to C is the array. So, if you want something where you can supply a key and get the value, you have to roll your own or find one on the Internet. The latter is probably preferable because you are likely to make mistakes and produce a slow data structure if you roll your own (especially if you are a beginner).

To give you a flavour of what you'll end up with, here's a simple example:

You'll need something to represent the collection; call it a ListMap for now:

struct ListMap;

The above is called an incomplete type. For now, we are not concerned with what's in it. You can't do anything with it except pass pointers to instances around.

You need a function to insert items into your collection. Its prototype would look something like this:

bool listMapInsert(struct ListMap* collection, int key, const char* value);
// Returns true if insert is successful, false if the map is full in some way.

And you need a function to retrieve the value for any one key.

const char* listMapValueForKey(struct ListMap* collection, int key);

You also need a function to initialise the collection:

struct ListMap* newListMap();

and to throw it away:

void freeListMap(struct ListMap* listMap);

The hard bit is implementing how those functions do what they do. Anyway, here's how you would use them:

struct ListMap* myMap = newListMap();
listMapInsert(myMap, 1, "foo");
listMapInsert(myMap, 1729, "taxi");
listMapInsert(myMap, 28, "perfect");

char* value = listMapValueForKey(myMap, 28); // perfect
freeListMap(myMap);

Here's a simple implementation. This is just for illustration because I haven't tested it and searching for entries increases linearly with the number of entries (you can do much better than that with hash tables and other structures).

enum
{
    listMapCapacity = 20
};
struct ListMap
{
    struct key_value kvPairs[listMapCapacity];
    size_t count;
};

struct ListMap* newListMap()
{
    struct ListMap* ret = calloc(1, sizeof *ret);
    ret->count = 0; // not strictly necessary because of calloc
    return ret;
}

bool listMapInsert(struct ListMap* collection, int key, const char* value)
{
    if (collection->count == listMapCapacity)
    {
        return false;
    }
    collection->kvPairs[count].key = key;
    collection->kvPairs[count].value = strdup(value);
    count++;
    return true;
}

const char* listMapValueForKey(struct ListMap* collection, int key)
{
    const char* ret = NULL;
    for (size_t i = 0 ; i < collection->count && ret == NULL ; ++i)
    {
        if (collection->kvPairs[i].key == key)
        {
            ret = kvPairs[i].value;
        }
    }
    return ret;
}

void freeListMap(struct ListMap* listMap)
{
    if (listMap == NULL)
    {
        return;
    }
    for (size_t i = 0 ; i < listMap->count ; ++i)
    {
        free(listMap->kvPair[i].value);
    }
    free(listMap);
}
underscore_d
  • 6,309
  • 3
  • 38
  • 64
JeremyP
  • 84,577
  • 15
  • 123
  • 161
1
typedef struct key_value
{
   int key;
   char* value;
}List;

struct key_value k1;
struct key_value k2;
struct key_value k3;

k1.key = 1;
k1.value = "foo";
k2.key = 2;
k2.value = "sec";
k3.key = 3;
k3.value = "third";

You will need to create N times the struct and give them values the way you did the first one. Or create array with N structs and iterate assign it values with a loop.

Array:

List arr[29];

int i;
for(i = 0;i<=28;i++){
    arr[i].key = i;
    arr[i].value = "W/e it needs to be";
}
du4ko
  • 101
  • 6
  • 1
    Yeah, using an array would be far superior to creating an arbitrary number of separate `struct`s that share no relation other than their names, which don't matter to the compiler. That would make for a better example. – underscore_d Jun 05 '17 at 12:05
  • Yeah, agree just added it. I was thinking he will be gaining value from understanding that he can create multiple structs. The way he formated his question I highly doubt he has any clue what struct is. – du4ko Jun 05 '17 at 12:07
1

"I have to store 30 key/value pair"

Create an array of struct e.g., key_value.

struct key_value
{
    int key;
    char* value;
};

struct key_value kv[30];

kv[0].key = 1;
kv[0].value = "foo";

printf("%s", kv[0].value);

You can loop through to assign values to keys and values. Access to whatever is in kv is simple.

int i = kv[0].key`;// copy value of k[0].key to i
char *v = kv[0].value; // copy value of k[0].value to v;
ytobi
  • 535
  • 1
  • 9
  • 19
1

The functionality you are looking for needs your own implementation in C; e.g. an array of your struct-type.
Here is an example of how to read the value for a key, without knowing anything about at which array-index the key will be found.
I have the keys numbered backward in order to illustrate that.

Note that more sophisticated API definitions are needed for special cases such as non-existing key; I just blindly return the last entry to keep things easy here.

#include <stdio.h>

#define MAPSIZE 30

struct key_value
{
   int key;
   char* value;
};

struct key_value kvmap[MAPSIZE];

void initmap(void)
{
    int i;
    for(i=0; i<MAPSIZE; i++)
    {
         kvmap[i].key=MAPSIZE-i-1;
         kvmap[i].value="unset";
    }

    kvmap[0].value="zero";
    kvmap[1].value="one";
    kvmap[2].value="two";
    kvmap[3].value="three";
    kvmap[4].value="four";
    kvmap[5].value="five";
    kvmap[6].value="six";
    kvmap[7].value="seven";
    kvmap[8].value="eight";
    kvmap[24].value="find this"; // it has the key "5"

}

char* readmap(int key)
{
    int i=0;
    while ((i<MAPSIZE-1) && (kvmap[i].key!=key))
    {   printf("Not in %d\n", i);
        ++i;}

    // will return last entry if key is not present
    return kvmap[i].value;
}

int main(void)
{
    initmap();

    printf("%s\n", readmap(5));
    return 0;
}
Yunnosch
  • 26,130
  • 9
  • 42
  • 54
0

Your code already have the method to acess the values.

kv.key = 1 
kv.value = "foo"

To get the values assigned is simple

kv.key
kv.value

It is a simple struct, if you wanna something like python dict you will need to implement a hash struct which will be more complicated.

Caio Belfort
  • 535
  • 2
  • 10