Variable Sized Struct C++

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;
}

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].

C++ variable length arrays in struct

You want a fairly low level thing, an ARP packet, and you are trying to find a way to define a datastructure properly so you can cast the blob into that structure. Instead, you can use an interface over the blob.

struct ArpHeader {
mutable std::vector<uint8_t> buf_;

template <typename T>
struct ref {
uint8_t * const p_;
ref (uint8_t *p) : p_(p) {}
operator T () const { T t; memcpy(&t, p_, sizeof(t)); return t; }
T operator = (T t) const { memcpy(p_, &t, sizeof(t)); return t; }
};

template <typename T>
ref<T> get (size_t offset) const {
if (offset + sizeof(T) > buf_.size()) throw SOMETHING;
return ref<T>(&buf_[0] + offset);
}

ref<uint16_t> hwType() const { return get<uint16_t>(0); }
ref<uint16_t> protType () const { return get<uint16_t>(2); }
ref<uint8_t> hwAddrLen () const { return get<uint8_t>(4); }
ref<uint8_t> protAddrLen () const { return get<uint8_t>(5); }
ref<uint16_t> opCode () const { return get<uint16_t>(6); }

uint8_t *senderHwAddr () const { return &buf_[0] + 8; }
uint8_t *senderProtAddr () const { return senderHwAddr() + hwAddrLen(); }
uint8_t *targetHwAddr () const { return senderProtAddr() + protAddrLen(); }
uint8_t *targetProtAddr () const { return targetHwAddr() + hwAddrLen(); }
};

If you need const correctness, you remove mutable, create a const_ref, and duplicate the accessors into non-const versions, and make the const versions return const_ref and const uint8_t *.

How to get the length of a variable size array of structs?

Instead of using "String" (Whatever that is in your case.), use a fixed array of char for each string.

Like so:

struct person
{
char name[32], /* string name has a length of 31 + 1 for NULL-termination */
char city[32], /* string city has a length of 31 + 1 for NULL-termination */
int age
}

compliant variable length struct in C++

What's wrong with simply doing a variant of the C way?

If the structure has to remain purely POD, the C way is fine.

struct var
{
int a;
int b[1];

static std::shared_ptr<var> make_var(int num_b) {
const extra_bytes = (num_b ? num_b-1 : 0)*sizeof(int);
return std::shared_ptr<var>(
new char[sizeof(var)+extra_bytes ],
[](var* p){delete[]((char*)(p));});
}

since it's a POD, everything works just like it did in C.


If b is not guaranteed to be POD, then things get more interesting. I haven't tested any of it, but it would look more or less like so. Note that make_var relies on make_unique, because it uses a lambda destructor. You can make it work without this, but it's more code. This works just like the C way, except it cleanly handles variable amounts of types with constructors and destructors, and handles exceptions

template<class T>
struct var {
int a;

T& get_b(int index) {return *ptr(index);}
const T& get_b(int index) const {return *ptr(index);}

static std::shared_ptr<var> make_var(int num_b);
private:
T* ptr(int index) {return static_cast<T*>(static_cast<void*>(&b))+i;}
var(int l);
~var();
var(const var&) = delete;
var& operator=(const var&) = delete;

typedef typename std::aligned_storage<sizeof(T), std::alignof(T)>::type buffer_type;
int len;
buffer_type b[1];
};
template<class T> var::var(int l)
:len(0)
{
try {
for (len=0; len<l; ++len)
new(ptr(i))T();
}catch(...) {
for (--len ; len>=0; --len)
ptr(i)->~T();
throw;
}
}
template<class T> var::~var()
{
for ( ; len>=0; --len)
ptr(i)->~T();
}
template<class T> std::shared_ptr<var> var::make_var(int num_b)
{
const extra_bytes = (num_b ? num_b-1 : 0)*sizeof(int);
auto buffer = std::make_unique(new char[sizeof(var)+extra_bytes ]);
auto ptr = std::make_unique(new(&*buffer)var(num_b), [](var*p){p->~var();});
std::shared_ptr<var> r(ptr.get(), [](var* p){p->~var(); delete[]((char*)(p));});
ptr.release();
buffer.release;
return std::move(r);
}

Since this is untested, it probably doesn't even compile, and probably has bugs. I'd normally use std::unique_ptr but I'm too lazy to make proper standalone deleters, and unique_ptr is hard to return from a function when the deleter is a lambda. On the off chance you want to use code like this, use a proper standalone deleter.

define struct with variable length vectors in C

Change struct S to have pointers to double:

struct S {
double *x;
double *y;
double z;
};

When creating a struct S, first create arrays for the members to point to:

double SampleX[] = { 1.,  2.,  3.,  4.  };
double SampleY[] = { 1.1, 2.2, 3.5, 4.0 };

Then define the structure with members pointing to that data:

struct S myS = { .x = SampleX, .y = SampleY, .z = 5.1 };

The designated initializers, .x = and so on, are unnecessary if you initialize all members in order, but they are shown here as an option.

Also add some way of knowing how many elements there are. If they can vary, routines that are passed this structure cannot know how many elements there are unless they are given that information in some way, such as via another member in the structure or some argument passed to the routine.

Creating the arrays for the members to point to can be done in additional ways to the one shown above. You can use compound literals:

struct S myS = {
.x = (double []) { 1., 2., 3., 4. },
.y = (double []) { 1.1, 2.2, 3.5, 4.0 },
.z = 5.1
};

or you can use malloc to allocate memory for the arrays. (If you use malloc, also use free to release memory when you are done with it, although that typically may be omitted when exiting the program.)



Related Topics



Leave a reply



Submit