4

I'm creating a dynamically allocated linked list where each item has a data element. Most of these elements are fixed size char arrays but some can be of varying length, E.g. only 1 or 2 chars - or 1000+.

If I use a union inside the data element with static and dynamic char array – is it always going to occupy:

  • size of the static one or if malloc'd the size of the malloced one?
  • size of the static one + if malloc'd the size of the malloced one?
  • the size of the pointer to the malloced one or the size of the static one?
  • ... (and so on)

A simplified example without the list. This is not how I'm filling it with data, - only as an example of the struct union.

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

enum meta_type {LIST, STRING};

struct meta {
    union {
        char clist[128];
        char *cstr;
    } val;
    enum meta_type type;
};

int init_meta(struct meta *meta, enum meta_type type, int size, char *data)
{
    if (type == STRING) {
        if ((meta->val.cstr = malloc(size + 1)) == NULL) {
            puts("Out of memeory");
            return 1;
        }
        sprintf(meta->val.cstr, "%s", data);
    } else {
        memset(meta->val.clist, 0, 128);
        meta->val.clist[0] = data[0];
        meta->val.clist[1] = data[1];
        meta->val.clist[2] = data[2];
    }

    meta->type = type;

    return 0;
}

void free_meta(struct meta *meta)
{
    if (meta->type == STRING)
        free(meta->val.cstr);
}

int main(int argc, char *argv[])
{
    struct meta meta;
    char list[] = {'a', '3', 'f'};

    if (argc > 1) {
        if(init_meta(&meta, STRING, strlen(argv[1]), argv[1]))
            return 1;
    } else {
        init_meta(&meta, LIST, 0, list);
    }

    fprintf(stdout,
        "meta[%d]: %s\n",
        meta.type,
        meta.type == LIST ? meta.val.clist : meta.val.cstr
    );

    free_meta(&meta);

    return 0;
}

@Floris: One of the whacky ways I tested:

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

enum meta_type {LIST, STRING};

#define SIZE_CLIST  128

struct meta {
    enum meta_type type;
    union {
        char clist[SIZE_CLIST];
        char *cstr;
    } val;
};

int init_meta(struct meta **meta, enum meta_type type, int size, char *data)
{
    if (type == STRING) {
        if (offsetof(struct meta, val) == 0) {
            puts("Ups.");
            return 2;
        }
        *meta = malloc(sizeof(struct meta) -
                SIZE_CLIST +
                sizeof(char *)
            );
        (*meta)->val.cstr = malloc(size + 1);
        if ((*meta)->val.cstr == NULL) {
            puts("Out of memeory");
            return 1;
        }
        sprintf((*meta)->val.cstr, "%s", data);
        puts((*meta)->val.cstr);
    } else {
        *meta = calloc(1, sizeof(struct meta));
        (*meta)->val.clist[0] = data[0];
        (*meta)->val.clist[1] = data[1];
        (*meta)->val.clist[2] = data[2];
    }

    (*meta)->type = type;

    return 0;
}

void free_meta(struct meta *meta)
{
    if (meta->type == STRING)
        free(meta->val.cstr);
    free(meta);
}

int main(int argc, char *argv[])
{
    struct meta *meta = NULL;
    char list[] = {'a', '3', 'f'};

    if (argc > 1) {
        if(init_meta(&meta, STRING, strlen(argv[1]), argv[1]))
            return 1;
    } else {
        init_meta(&meta, LIST, 0, list);
    }

    fprintf(stdout,
        "meta[%d] %d: %s\n",
        meta->type,
        sizeof(*meta),
        meta->type == LIST ? meta->val.clist : meta->val.cstr
    );

    free_meta(meta);

    return 0;
}
3
  • A pointer to a malloced array only takes the space of the pointer - you don't know where the memory block is located that is pointed to. So I'm pretty sure then answer is your third option. Did you try this to see? What did you find? Commented Mar 8, 2013 at 12:50
  • @Floris: Yes, tried various, problem is to see exactly the size of an object. Though, as I plan to malloc each data element I should have taken the hint of simply printing a sizeof(struct meta). I'm slow today. Tried something else for the fun of it, - but not going to use it as it is to hackish. I'll write a mini memory manager instead with pre-allocated size of N where I point each data element to and allocate more on need. Updated with the "hackish thing". Commented Mar 8, 2013 at 14:09
  • I agree - "hackish thing" indeed. I thought I was the only one to write code like that... Thanks for sharing - and glad you got your answer. Commented Mar 8, 2013 at 22:14

1 Answer 1

2

A union will allocate space for largest member. You've got an array and a pointer, so it'll allocate space for the array. A pointer is fixed in size, it doesn't matter what it points to.

When you use malloc the space isn't allocated inside a data structure, it's somewhere else in memory. You assign that memory location to the pointer.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. How I thought then. In other words going to be memory inefficient if having loads of small data members in the list. Have to rethink my entire application here ;P

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.