Allocating Struct with Variable Length Array Member

Struct with variable size of array

Do you mean something like this?

typedef struct{
int plistSize;
double* plist;
} ParticleList;

int main()
{
int i, z = 0;

/* Assuming you have three lists with three different sizes */
double list1[2] = {-1.0, -1.1};
double list2[3] = {-2.0, -2.1, -2.2};
double list3[4] = {-3.0, -3.1, -3.2, -3.3};

/* Create an array of three Particle Lists */
ParticleList pl[3] = {{list1, 2},{list2, 3},{list3, 4}};

/* Access the values in the Particle Lists */
for(i = 0; i < 3; i++)
{
printf("ParticleList pl[%i]:\n", i);

for(z = 0; z < pl[i].plistSize; z++)
{
printf("pl[%i].plist[%i] = %f\n", i, z, pl[i].plist[z]);
}
}

/* Change the first item of the second list */
pl[1].plist[0] = 2.3;
}

This way you can access each item in each list by

pl[<index of list>].plist[<index of list item>]

A bit more dynamic by using flexible array members (this way one of the lists can be replaced by another list of different size):

Note that I changed the struct!

typedef struct{
int plistSize;
double plist[];
} ParticleList;

int main()
{
int i, z = 0;
ParticleList *pl[3];

/* Allocate memory for the lists */
pl[0] = malloc( sizeof(ParticleList) + sizeof(double[2]) );
pl[0]->plistSize = 2;
pl[1] = malloc( sizeof(ParticleList) + sizeof(double[3]) );
pl[1]->plistSize = 3;
pl[2] = malloc( sizeof(ParticleList) + sizeof(double[4]) );
pl[2]->plistSize = 4;

/* Write the values in the Particle Lists */
for(i = 0; i < 3; i++)
{
printf("ParticleList pl[%i]:\n", i);

for(z = 0; z < pl[i]->plistSize; z++)
{
pl[i]->plist[z] = -i;
}
}

/* Print the values */
for(i = 0; i < 3; i++)
{
printf("ParticleList pl[%i]:\n", i);

for(z = 0; z < pl[i]->plistSize; z++)
{
printf("pl[%i]->plist[%i] = %f\n", i, z, pl[i]->plist[z]);
}
}

/* Change the first value of the second list */
pl[1]->plist[0] = -1.1;

/* Replace the first list by a new one */
free(pl[0]);
pl[0] = malloc( sizeof(ParticleList) + sizeof(double[5]) );
pl[0]->plistSize = 5;

/* Assign some new values to the new list 1 */
pl[0]->plist[0] = -4.1;
pl[0]->plist[1] = -4.2;
pl[0]->plist[2] = -4.3;
pl[0]->plist[3] = -4.4;
pl[0]->plist[4] = -4.5;

/* Print the values */
for(i = 0; i < 3; i++)
{
printf("ParticleList pl[%i]:\n", i);

for(z = 0; z < pl[i]->plistSize; z++)
{
printf("pl[%i]->plist[%i] = %f\n", i, z, pl[i]->plist[z]);
}
}

/* free all lists before exiting the program */
for(i = 0; i < 3; i++)
{
free(pl[i]);
}

return 0;
}

How to allocate memory for a struct with a member of unknown variable size?

Instead of an array, you can have a pointer inside your struct:

struct base {
...
char *path;
};

Later, allocate memory to this pointer whenever you need it:

base.path = malloc(n * sizeof(char)); // n is the variable size you will set before

Since you allocate memory dynamically now, don’t forget to free to avoid any memory leaks. In C, there is the requirement of every struct having a fixed byte length, so that, for example, sizeof(struct base) can be evaluated at compile time. In your case, the variable length array's size cannot be determined at compile time, so it is illegal do something like char path[l] where l is unknown at compile time.

Btw, a correction regarding

l = sizeof( db[i]->path );

First of all, even if path was declared as an array, this won't give you the size of it in terms of its length, it would return you the complete byte size occupied by the array, you gotta divide it by sizeof (char) to get the length. Now that you have declared it as a pointer however, I guess you don't really need to do this.

returning struct with multiple variable length arrays from function in C

First, you don't actually have two variable length arrays in your struct. It would be an error if you did. What you actually have is two pointers, each of which may point to the first element of an array of any size.

The problem you're having is that you're taking arrays created as local variables in the field function and assigning them (or more accurately pointers to their first elements) to the struct which is being returned. This means you're returning the address of local variables from the function. The lifetime of these locals end when the function exits, so the memory those pointers points to is invalid (and in fact the pointer values themselves are indeterminate) and attempting to dereference those pointers triggers undefined behavior.

Also note that a variable length array cannot be initialized.

You need to dynamically allocate space for the A and B fields and write to those arrays. You can however use the existing local arrays to perform a memcpy if you don't want to copy individual members.

struct fields field() {
double A[4] = { 1, 2, 3, 4 };
double B[4] = { 1, 2, 3, 4 };

struct fields field;
field.n = 4;
field.A = malloc(sizeof A);
field.B = malloc(sizeof B);
memcpy(field.A, A, sizeof A);
memcpy(field.B, B, sizeof B);
return field;
}

Array of variable length in a structure

i would suggest an alternative like this:

typedef struct 
{
int width;
int height;
struct pixel *pixels;
} image;

every time, you need to alloc:

image img;
/* init */
img.pixels=malloc(sizeof(struct pixel)*img.width*img.height);

*(img.pixels+img.height*i+j) represents img.pixels[i][j].

struct with variable length array in std::variant

As has been pointed out, this is not legal C++. It just wont work this way. However, if the amount of entries is bound, it might be possible to do this:

template <std::size_t N>
struct Data {
int members;
static constexpr std::size_t entries_size = N;
Entry entries[N];
}; // Of couse, you might want to use std::array<Entry,N> instead!

// ...
std::variant<Data<2>, Data<8>, Data<32>> example;

This, of course, is highly situational. If you know the incoming data will fall into either 2, 8 or 32 entries, you can specify these at compile time. If the amount of entries is completely variable, with no guarantees, use std::vector. That's what it's for.

Would allocating the length of an array inside a struct, with one of the member variables of the struct, work?

A struct can't be created with a variable length array. Otherwise different instances of the struct could potentially be different sizes, which is not allowed. There is a construct called a flexible array member which is allowed, but only for the last field in a struct.

The way you attempted to set things up isn't correct anyway from the perspective of the data format. You have an array of router IDs, but the diagram shows groups of a router ID followed by two ports, a cost, and an IP address. With this setup, you actually could use a flexible array member as follows:

struct __attribute__((__packed__)) router {
uint16_t ID;
uint16_t port1;
uint16_t port2;
uint16_t cost;
uint32_t IP_addr;
};

struct __attribute__((__packed__)) INIT_HEADER {
uint16_t rounter_n;
uint16_t update_interval;
struct router routers[];
};

You can then take an unsigned byte array and cast it to a pointer to this struct.

Keep in mind however that, assuming this data structure is received over a network, you'll most likely need to call ntohs and ntohl on each of the uint16_t and uing32_t fields respectively in order to extract the proper values.

Also, as was mentioned in other answers, by doing this you run the risk of the structure not matching up exactly with the received data due to padding in the struct.

For more details on structure packing, see this guide.



Related Topics



Leave a reply



Submit