0

I have problem in accessing the pointer to a structure (array passed to function) that has a variable size array.

        char name[20];
        char value[20];
   }param_t;
   typedef struct object {
        char name[20];
        int no_of_params;
        param_t params[];
   };

int main()
{
    int no_of_objs = 3, no_of_params = 5;
    object_t *objs = malloc(no_of_objs * (sizeof(object_t) + (no_of_params * sizeof(param_t)) );
     //...
     //...

     objs++;  //Increment to point to the next item <-- Problem: ignores params[] size

     // blah
     // blah
     // blah

I have allocated memory to have 3 object_t with each object_t storing 5 param_t.

Memory allocation is fine and I could set values to the members. objs[0] is perfectly fine. Now if I increment the objs (objs++) to point to next object, it actually points to previous object's param address. It completely ignores the params[]. Now if I set values for the second *objs, it actually overwrites the params[] of previous *objs.

My question is: Is this a bug in C compiler? If not, how do I traverse the objs?

1
  • Apart from the sizeof problems, it is quite likely that &objs[0].params[objs[0].no_of_params] will not meet the alignment requirements for the following object_t. Commented Sep 12, 2019 at 16:21

3 Answers 3

1

It's not a bug in the C compiler, just a drawback of using variable length arrays.

Compilers are allowed to treat the variable length array member of the struct as not contributing to the sizeof.

This effectively breaks pointer arithmetic, and it means you can't easily "traverse the objects", as you put it.

That's life I'm afraid. A good enough reason for dropping variable length arrays as a compulsory requirement from C11.

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

1 Comment

I agree it is quite a task. I think one should avoid variable length arrays unless absolutely required.
0

As per the answer of Bathsheba, you could better implement it as an array of pointers to the objects:

int no_of_objs = 3, no_of_params = 5;
object_t **objs = malloc(no_of_objs * sizeof(object_t *);
for (int i=0; i<no_of_objs; i++)
    objs[i]= malloc ((sizeof(object_t) + (no_of_params * sizeof(param_t)) );

Comments

0

If you really need to allocate this memory as a single block, you need to determine a suitably aligned element size:

size_t object_t_size(size_t nparams)
{
    return (offsetof(object_t, params[nparams]) | (_Alignof(object_t) - 1)) + 1;
}

Here, nparams is the number of param_t elements allocated for the params flexible array member of object_t.

For traversing forwards through a block of memory containing a collection of object_ts with params flexible array members, you need a way to find the position of the next object_t:

object_t *next_object_t(object_t *obj, size_t nparams)
{
    return (object_t *)((char *)obj + object_t_size(nparams));
}

The above can be used even if the object_ts have different sizes (including their params flexible array member) as long as the sizes of each individual object_t is known and does not change after allocation (or at least, not without code to reallocate the memory and shuffle around the contents to expand or reduce the size of a particular object_t).

If all the object_ts in the collection have the same size (including the fixed size of their params flexible array member), you can get a pointer to the ith element:

object_t *indexed_object_t(object_t *base, size_t nparams, size_t idx)
{
    return (object_t *)((char *)base + object_t_size(nparams) * idx);
}

Note that the above function is unsuitable for indexing backwards from an arbitrary element. That could be fixed by using a signed type for the index and casting the return value of object_t_size to a suitably wide signed integer type:

object_t *indexed_object_t(object_t *base, size_t nparams, int idx)
{
    return (object_t *)((char *)base + (intmax_t)object_t_size(nparams) * idx);
}

1 Comment

Typecast to char* and manual increment is a good technique. It does the trick. Thanks. Now I'm on to variable length array in the param_t (nested structures with both having variable length array) :)

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.