sitilge
sitilge

Reputation: 3737

Structure that mimics two flexible arrays in a struct in C

Currently, I have a struct camera that holds two fixed size variables f and p

struct point {
    double x, y, z;
};

struct camera {
    struct point f[5], p[5];
};

Making f and p flexible results in error. I followed the instructions given in this SO question and decided to go for non-struct variables and pass them to functions instead which resulted in long function call syntax and messy structure.

My question, although subjective, is: what is the best approach to have two flexible arrays that can be accessed via one point (similar to struct, etc.)?

Upvotes: 1

Views: 716

Answers (3)

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726489

Here is an approach that mimics two flexible arrays of identical type: make one flexible array that holds both arrays, and add a pointer into the array at the position where the second flexible array starts:

struct camera {
    struct point *p;
    struct point f[];
};

When you allocate camera, provision the space for both arrays, and add it to the "raw" sizeof(struct camera). Let's say your first array has n elements, and the second one has m. Then you initialize your camera as follows:

struct camera *c = malloc(sizeof(*c)+(n+m)*sizeof(struct point));
c->p = &(c->f[n]); // Point "p" to the beginning of the second array
for (int i = 0 ; i != n ; i++) {
    c->f[i] = ... // Init points in f
}
for (int i = 0 ; i != m ; i++) {
    c->p[i] = ... // Init points in p
}

Upvotes: 1

chux
chux

Reputation: 153348

A non flexible array approach follows that, IMO, addresses OP's higher level problem of "long function call syntax and messy structure" with a cleaner pair of struct point pointers.

struct camera {
    size_t size;  // add size member
    struct point *f;
    struct point *p;
};

bool camera_initialize(struct camera *cam, size_t size) {
  // Use 1 or 2 allocations
  cam->f = malloc(sizeof *(cam->f) * 2 * size);
  if (cam->f) {
    cam->p = cam->f + size;
    cam->size = size;
    return false; // success 
  } else {
    cam->p = cam->f = NULL;
    cam->size = 0;
    return size > 0; // fail if size was not 0
  }
}

void camera_uninitialize(struct camera *cam) {
  free(cam->f);
  cam->p = cam->f = NULL;
  cam->size = 0;
}

Sample usage

int main() {
  size_t n  = foo();
  struct camera cam;
  if (camera_initialize(&cam, n)) return EXIT_FAILURE;
  bar(cam.f, cam.n);
  bar(cam.p, cam.n);
  camera_uninitialize(&cam);
}

Upvotes: 2

By definition you can't have two flexible array members. A flexible array member must be the last in the structure, there can only be a single "last" element.

But I sense you apparently need to pair up f and p, so why not aggregate them? Then you can have a flexible array member of those pairs:

#include <stdio.h>
#include <stdlib.h>

struct point {
    double x, y, z;
};

struct camera {
    char dummy;
    struct {
        struct point f, p;
    } pairs[];
};

int main(void) {
    struct camera *c = malloc(sizeof(*c) + sizeof(c->pairs[0])*5);

    return 0;
}

Note the use of C99's support for flexible array members.

Upvotes: 2

Related Questions