Jean
Jean

Reputation: 22695

Dynamically allocate structure and array in it in C

  1. How will I dynamically allocate an array of struct Register with each register having a dynamically allocated array of struct Field ?
  2. How will I access each of these members (Can I use Register_A.FieldArray[23].High?)?
  3. How will I initialize register structure efficiently(assuming that register struct array is a big one) ? (Like a data segment without spending any compute)

    struct Field
    {
        char    High;                
        char    Low;                
        char    Attribute;
    };
    
    struct Register 
    {
       unsigned int    ResetValue;
       struct Field    FieldArray[];
    };
    

Upvotes: 2

Views: 1999

Answers (4)

Kevin
Kevin

Reputation: 56069

I strongly discourage you from using a flex array, because they're nothing but a kludge. You should instead declare and use it as a struct Field *, mallocing it to size like any other dynamic array.

That said, to malloc with an array size of n_elem:

struct Register register = malloc(sizeof(*register) + n_elem * sizeof(*register->FieldArray));

To access the elements:

char high = register->FieldArray[0].High;

For initialization: in gcc, at least, you can initialize the array part statically like any other static array. I'm not sure how other compilers handle it.


Why flex arrays are discouraged:

I'll link this post, but I don't think the answer is complete (most of the discouragement is because it's c-99 only), so I'll add my thoughts.
They are an exception. In essence, you're declaring the array to be of zero size and accessing it out of bounds every time, just to an extent you have allocated for. You can't use a struct with a flexible array just like any other struct, e.g. you can't take the sizeof the flexible array. If you declare a static one or an array of them, you can't use the array member because there's no space allocated for it.

Example of using them in an array:

#include <stdio.h>

struct test {
        int val;
        int arr[];
};

int main() {
        struct test tarr[2];
        printf("%p\n%p\n", &tarr[0].arr[0], &tarr[1].val);
}

Output:

0x7fff59b67164
0x7fff59b67164

They are at the same address. If you try to write to the array member, you overwrite the next object. If you try to read from it, you read data from the next object. Depending on padding, this could even be a nonsense value from the padding.

They're like goto statements, both are potentially useful but more often a bad idea. If you don't know why they're dangerous, you shouldn't be using them (in real code; it's not a bad idea to play around with them in a test program to see how to use them correctly and how they can introduce problems).

Upvotes: 3

Jens Gustedt
Jens Gustedt

Reputation: 78923

Flexible array members are a part of C99.

  1. you can allocate a struc with flexible array member just as you think you should: malloc(sizeof(struct Register) + sizeof(struct Field[n])), where n is the size you want. Don't forget to initialize the array and to keep track of n, best by dedicating a member to that purpose
  2. yes

BTW: the malloc above may be wasting some bytes due to padding, but usually it is not worth thinking about the exact formula. The minimal one has a max and uses offsetof.

Upvotes: 0

user142162
user142162

Reputation:

A way to do it is by changing the size of the struct Register:

struct Register 
{
   unsigned int    ResetValue;
   struct Field    FieldArray[1];
};
struct Register *Register_Create()
{
    struct Register *reg = calloc(1, sizeof(struct Register) - sizeof(struct Field));
    // check for NULL pointer
    return reg;
}

struct Register *Register_SetSize(struct Register *reg, size_t size)
{
    // check for NULL
    reg = realloc(reg, sizeof(struct Register) + sizeof(struct Field) * (size - 1));
    // check for NULL
    return reg;
}

Here's an example on how to use this:

struct Register *reg = Register_Create();
reg = Register_SetSize(register, 5);
// You now have space for 5 elements in reg->FieldArray
reg->FieldArray[3].High = 'B';

Keep in mind that this solution only works if FieldArray is placed at the end of the struct.

Upvotes: 1

TJD
TJD

Reputation: 11896

You are going to have to know how big the FieldArray is. If it isn't fixed, you need to declare with max value. Then you can just alloc a Register and access as you specified

Upvotes: 0

Related Questions