#include <stddef.h>
#include <stdlib.h>

/*** Constants */
enum e_rgb {
    Red,
    Green,
    Blue,
    RGBCount
  };

/*** Object types */
typedef unsigned char rgb[RGBCount];

/*** Function declarations */
struct s_picture * alloc_picture(int w, int h);
rgb * picture_row(struct s_picture * pic, int row);

/*** Struct/union definitions */
struct s_picture {
    int width;
    int height;
    rgb * data;
  };

/*** Function definitions */
int main(void) {
    struct s_picture * pic;
    rgb * row_ten;

    /* Allocate a 10 x 10 picture */
    pic = alloc_picture(10, 10);
    if (!pic)
      return EXIT_FAILURE;

    /* Produce a pointer to the tenth row */
    row_ten = picture_row(pic, 9);

    /* The next three sections all do the same thing */
    Red[*row_ten] = 42;
    Green[*row_ten] = 42;
    Blue[*row_ten] = 42;

    row_ten[0][Red] = 42;
    row_ten[0][Green] = 42;
    row_ten[0][Blue] = 42;

    (*row_ten)[Red] = 42;
    (*row_ten)[Green] = 42;
    (*row_ten)[Blue] = 42;

    /* Clean-up and terminate */
    free(pic);
    return EXIT_SUCCESS;
  }

/* Allocate storage for a picture */
struct s_picture * alloc_picture(int w, int h) {
    /* Wrap up a picture */
    struct s_wrapper {
        struct s_picture pic[1];
        /* This member is here for alignment */
        rgb data[1];
      };
    size_t size;
    void * ptr;
    struct s_wrapper * wrapper;
    unsigned char * bytes;

    /* Compute the amount of storage to allocate */
    size = (
        /* Don't allocate for the alignment member */
        offsetof(struct s_wrapper, data)
        + sizeof wrapper->data * w * h
      );
    if (size < sizeof *wrapper)
      size = sizeof *wrapper;

    /* Allocate the storage */
    ptr = malloc(size);
    /* Return a null pointer on failure */
    if (!ptr)
      return ptr;

    wrapper = ptr;
    bytes = ptr;

    wrapper->pic->width = w;
    wrapper->pic->height = h;

    /* There is a problem with the next line */
    wrapper->pic->data = wrapper->data;
    /*
     * Since there is only one element for 'wrapper->data',
     * that means that the pointer value yielded by that
     * expression could have such bounds associated with it.
     * Instead, we derive a pointer value from 'bytes', whose
     * bounds would be those of the call to 'malloc', above
     */
    wrapper->pic->data = (rgb *) (bytes + offsetof(struct s_wrapper, data));
    /* That was safer */

    return wrapper->pic;
  }

/* Produce a pointer to the specified row in a picture */
rgb * picture_row(struct s_picture * pic, int row) {
    return pic->data + row * pic->width;
  }
