3

I am trying to define an array using pointer instead of size declaration because I do not know how many elements a map might have. Tried linked list but was not successful. I am sorry if this is a report. I am a newbie please excuse if it looks like a stupid question.

#include<stdio.h>

typedef struct _keyValue
{
    char *key;
    char *value;
} _keyValue;

typedef struct _keyValues
{
    /* _keyValue keyValue[5];  - This works*/
    _keyValue *keyValue;
    int size;
} _keyValues;

_keyValues map;

main()
{
    map.keyValue[0].key     = "Key One";
    map.keyValue[0].value   = "Value One";

    map.keyValue[1].key     = "Key Two";
    map.keyValue[1].value   = "Value Two";

    map.size = 2;

    printf("Key: %s Value: %s", map.keyValue[0].key, map.keyValue[0].value);
}
2
  • Don't use names starting with underscores; they are essentially reserved for use by 'the implementation'. Commented Jun 11, 2013 at 14:22
  • Also, be more specific with the question; "Tried linked list but was not successful" does not provide enough information for somebody to answer your question. Commented Jun 11, 2013 at 14:26

3 Answers 3

5

map.keyValue in your example is an uninitialised pointer. You need to provide storage for the array by allocating memory using malloc

main()
{
    map.keyValue = malloc(sizeof(*map.keyValue) * 2);
    map.size = 2;

    map.keyValue[0].key     = "Key One";
    map.keyValue[0].value   = "Value One";

You can later extend the array using realloc

int newMapSize = ...
_keyValue* temp = realloc(map.keyValue, sizeof(*map.keyValue) * newMapSize);
if (temp == NULL) {
    /* allocation failed.  Handle out of memory error and exit */
}
map.keyValue = temp;
map.size = newMapSize;
// map.keyValue[0..newMapSize-1] are now available
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you very much. Appreciate quick reply.
If you are going to use this approach where you realloc memory a standard implementation is to double the number of elements when you need more space.
Yes, one common approach is to double your storage every time you realloc(). Other common approaches are to grow your storage by a factor of 1.5, or to increase by a fixed or sliding number of elements. Which strategy is best in any given case may depend on factors such as how rapidly your storage gets used, rate of growth increase, how large your elements are. Under some circumstances, it might even be best to implementing more than one of these strategies and choose between them at run time.
2

If you don't know how big they will be, then use dynamic allocation. Key functions here are malloc and free.

Here's a suggestion on how you can use your structs if you don't know how big they will be:

First have the following includes in your code:

#include <stdio.h>   /* for printf */ 
#include <string.h>  /* for strcpy, as you cannot directly assign strings to a malloc'd pointer */
#include <stdlib.h>  /* for malloc and free, for managing memory dynamically */

Then we define the size of the keys and values:

const int key_size   = 10; /* let's define how big our keys and values will be */
const int value_size = 25;

And here is how you can use your structs:

map.size = 30; /* decide how many keyValues we will have */

map.keyValue = malloc(sizeof(_keyValue) * map.size);   /* create storage big enough for 30 _keyValue structs
                                                        * malloc will allow you to assign memory to key and treat it as an array
                                                        * malloc assigns memory from the heap
                                                        * equal to the size specified (30), 
                                                        * this can be potentially as large as your computer's memory */

map.keyValue[0].key = malloc(sizeof(char) * key_size); /* let's create a key at position 0 */

strcpy(map.keyValue.key, "some key"); /* copying some values into key */

map.keyValue[0].value = malloc(sizeof(char) * value_size); /* let's create some space for a value for the 0th element */

strcpy(map.keyValue.value, "some value");


... /* you process and work with those values as you see fit */

free(map.keyValue[0]) /* malloc assigned memory needs to be returned to the OS as it's manually managed, 
                       * here we free the element at position 0 we created earlier
                       * if you have more than element here use a loop e.g: 
                       * for (int i = 0; i < map.size; i++) { free(map.KeyValue[i]) }
                       */


free(map.keyValue); /* free the keyValue itself that stored all the keyValue structs*/

One tip, declarations starting with an underscore are discouraged as they are reserved for the language.

Comments

1
#include <stdlib.h>

int main(void){
    map.size = 2;
    map.keyValue = malloc(sizeof(_keyValue)*map.size);

    map.keyValue[0].key     = "Key One";
    map.keyValue[0].value   = "Value One";

    map.keyValue[1].key     = "Key Two";
    map.keyValue[1].value   = "Value Two";


    printf("Key: %s Value: %s", map.keyValue[0].key, map.keyValue[0].value);

    return 0;
}

if I do not know the size

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

int main(void){
    char buff[128] = "";

    map.size = 5;//decide the size temporarily
    map.keyValue = malloc(sizeof(_keyValue)*map.size);

    int count = 0, retv;
    while(1){
        printf("input key : ");
        retv=scanf(" %127s", buff);
        if(retv != 1 || strcmp(buff, "end")==0) break;
        map.keyValue[count].key = strdup(buff);
        printf("input value : ");
        scanf(" %127s", buff);
        map.keyValue[count].value = strdup(buff);
        ++count;
        if(count == map.size)//full
            map.keyValue = realloc(map.keyValue, sizeof(_keyValue)*(map.size+=5));//increase the size
    }

    int i;
    for(i=0;i<count;++i)
        printf("Key: %s Value: %s\n", map.keyValue[i].key, map.keyValue[i].value);

    //dealloc
    for(i=0;i<count;++i){
        free(map.keyValue[i].key);
        free(map.keyValue[i].value);
    }
    free(map.keyValue);

    return 0;
}

3 Comments

Your suggested code looks correct but an additional explanation of what has changed and why would make it much more valuable to the OP.
What if I do not know the size of the map upfront and use loop to populate the value.
@MeUnagi you and i(;-p) have a good explanation simonc. You can extend by realloc the area secured for the time being if the size is unknown in advance.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.