1
votes

I have a struct that stores some data as a void pointer and a integer like this:

 struct container
 {
   int size;
   void* data;
 };

Now I have a second struct:

 struct date
 {
   int day;
   int year;
 };

And I have function that initialized such a container and returns it:

struct container get_container()
{
    struct container d = { .data=  {(struct date){.day = 1, .year = 2}, (struct date){.day = 4, .year = 5}}, .size = 2};
    return d;
}

But when I compile the code the compiler complains that types mismatch:

test.c:19:34: error: initializing 'void *' with an expression of incompatible type 'struct date'
        struct container d = { .data=  {(struct date){.day = 1, .year = 2}, (struct date){.day = 4, .year = 5}}, .size = 2};
                                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.

Even if I a void* cast to the init it doesn't work. Is there any way to do this, without using malloc?

2

2 Answers

4
votes

To get the initializer to compile, you will need to use compound literals (which were also added to C99 alongside the designated initializers you are using):

struct container d =
{
    .data = (struct date[]){ { .day = 1, .year = 2 }, { .day = 4, .year = 5 } },
    .size = 2
};

It is harder to determine whether returning a copy of that structure is 'safe'. The issue is whether the array of dates continues to exist after the function returns (it doesn't) and whether it can safely be modified by the code that gets a pointer returned (it can).

Thanks to 2501 for pointing out where to look in his comment.

ISO/IEC 9899:2011

§6.2.4 Storage durations of objects, ¶6 [discussing automatic duration objects] …If an initialization is specified for the object, it is performed each time the declaration or compound literal is reached in the execution of the block; otherwise, the value becomes indeterminate each time the declaration is reached.

§6.5.2.5 Compound literals, ¶5 The value of the compound literal is that of an unnamed object initialized by the initializer list. If the compound literal occurs outside the body of a function, the object has static storage duration; otherwise, it has automatic storage duration associated with the enclosing block.

So, to return the pointer to the array of dates, you need to use explicit memory allocation (malloc() et al). Presumably, you will have other containers holding different types of data than just struct date — otherwise, you're abusing void * (use struct date * instead, or consider the merits of a flexible array member).

2
votes

You're attempting to assign a struct value to a void pointer, which wont work. You need to take the address of your struct and assign data to that instead. This means you need to use malloc. If you didn't use malloc you'd be taking a pointer to a local stack variable, which "disappears" once the function it was declared in ends and its frame is popped from the stack. At that point your pointer would not be pointing to what you expect.