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
Array of Pointers as Function Parameter
Why Does Pointer to Int Convert to Void* But Pointer to Function Convert to Bool
Segmentation Fault with Char Array and Pointer in C on Linux
What Does the Gcc Warning "Project Parameter Passing for X Changed in Gcc 7.1" Mean
How to Convert "Pointer to Pointer Type" to Const
Preferred Cmake Project Structure
Boost Asio - How to Write Console Server
How to Initialize the Reference Member Variable of a Class
Why Should I Avoid MACros in C++
Undefined Reference to Mempcy@Glibc_2.14 When Compiling on Linux
C++ Regex for Overlapping Matches
How to Do Static_Assert with MACros
Undefined Symbol on a Template Operator Overloading Function
C++11 Std::Threads VS Posix Threads
Significance of a .Inl File in C++
When to Use Const Char * and When to Use Const Char []
Cmake - Global Linker Flag Setting (For All Targets in Directory)