简体   繁体   中英

multiple flexible array in a struct in C?

I have multiple flexible arrays in s struct in c:

typedef struct
{
   int a;
   float b;
} Name;

typedef struct
{  
   int c;
   int d;
   int e;
} NIM;

typedef struct 
{
   int age;
   int time;
   Name name[1];
   NIM  nim[1];
} EthgenSig;

if we have need to allocate memory like this:

malloc(sizeof(EthgenSig) + sizeof(Name) * 10);

how the memory will be allocated and if we operator name array first and then we operate nim array later, then the nim[1] will overwrite the name array, then how to solve it?

You can't have more than one flexible-array member for the exact reason you pointed out.

At most, if you need your data to be kept all in the same memory block, you can make name and nim pointers and set where they point to the correct locations after allocation (making sure not to break any alignment constraint), but the simplest (and most sensible) thing is to just allocate separately the arrays for name and nim .

This is not so hard to do... the key is to realize that arrays and pointers in C both have very similar properties. In fact, array accessor notation has a direct correspondence to pointer notation:

a[b] == *(a + b);

Note that this has the effect of making the name of the array and the index interchangeable, so this is also true:

a[b] == b[a];

You can use this to achieve the result you want. First, declare a structure with two pointer elements. This provides two pointers that will store the base address of the two arrays:

struct two_blocks {
    int *x;
    int *y;
}

When you allocate this structure, you'll need to allocate extra space for the bodies of the two arrays:

#define X_SIZE 3
#define Y_SIZE 4

two_blocks *data = (two_blocks *)malloc(sizeof(two_blocks)
                                         + (sizeof(int) * X_SIZE)
                                         + (sizeof(int) * Y_SIZE));

And then the final step is to initialize the two array pointers. (These expressions use a lot of pointer type casting to ensure that the pointer arithmetic is done in single bytes. Pointer arithmetic is usually done in units of the size of the object being pointed to, to support the array/pointer equivalence I mentioned above.)

data->x = (int *)(((char *)data) + sizeof(two_blocks));
data->y = (int *)(((char *)data) + sizeof(two_blocks) + X_SIZE * sizeof(int));

From there, the arrays can be used like you'd expect:

 data->x[2] = 42;
 data->x[2] = 42;

A couple observations

  • Like Matteo said, be careful with alignment. Using this technique is taking memory layout over from the compiler, which can cause unexpected problems. If this caveat makes no sense to you, then you probably shouldn't use this technique.
  • One of the rationales for using this technique is that it can simplify memory management by reducing the number of frees you need to manage. If you know that your two arrays, x and y, both have the same lifecycle as their enclosing structure, then this removes one potential type of memory leak. (As well as reduces the chance of memory fragmentation by reducing the number of memory blocks.)

Having an array of size 1 is the same as not having an array at all when it comes to the memory layout of this struct.

You may as well have this:

typedef struct 
{
   int age;
   int time;
   Name name;
   NIM nim;
} EthgenSig;

But I'm assuming that is not what you want. It is pretty hard to tell what you actually want. But I'm assuming that you actually want this:

typedef struct 
{
   int age;
   int time;
   Name* name;
   NIM* nim;
} EthgenSig;

foo = malloc(sizeof(EthgenSig);
foo.name = malloc(sizeof(Name)*10);
foo.nim = malloc(sizeof(Nim) * 10);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM