-2

My name is Bob and I am a three-star programmer. Well, more accurately, I'm trying not to be. I have read a lot on the internet and this site about how "three-star programmer" is a Very Bad Thing. And I can see why. I have read very little (very little that's comprehensible, anyway) about how to avoid it. I mean, there are data sets out there that simply need three or more indices to access their values in a sane manner. So how do I deal with such a set?

I remember seeing a C macro a while back that allows you to store such a data set in a 1D array, and then access the data with three indices, something to the effect of a(i,j,k) is expanded to a[i*NZ*NY + j*NZ +k] but I can't remember how to write it and can't find it on the internet. Anyone know, or have a better idea?

Scheff's Cat
  • 19,528
  • 6
  • 28
  • 56
bob.sacamento
  • 6,283
  • 10
  • 56
  • 115
  • I believe the general advice is "Have one pointer to a struct". The struct contains a pointer to another struct, which contains a pointer to your third index data. In your case with indices, one 1d array of data is probably the better option though. But your math there is correct. – Mooing Duck Dec 11 '20 at 22:54
  • @MooingDuck Thank you. I was hoping the math was correct. But I am having trouble figuring out how to write the actual macro. Any ideas? Thanks. – bob.sacamento Dec 11 '20 at 22:56
  • This is silly to be concerned about to begin with, but even as you are: you're just trying to find a way to hide the three stars and haven't avoided being a "three-star programmer" with this macro you desire. – niets Dec 11 '20 at 23:07
  • 2
    You should describe your use case. If the data you are dealing with **is** a three-dimensional array, maybe you can actually use a three-dimensional array with array indexing like `a[i][j][k]` instead of using pointers. – Bodo Dec 11 '20 at 23:18

1 Answers1

1

My C is very poor, but wouldn't this simply be:

struct intArray3d {
    int NX;
    int NY;
    int NZ;
    int data[]; //or maybe it's data[0]?
};
intArray3d* newIntArray3d(int NX, int NY, int NZ) {
    int dataBytes = NX*NY*NZ*sizeof(int);
    intArray3d* array = malloc(sizeof(intArray3d) + dataBytes);
    array->NX = NX;
    array->NY = NY;
    array->NZ = NZ;
    memset(array->data, 0, dataBytes);
    return array;
}
int intArray3dGet(intArray3d* array, int x, int y, int z) {
    assert(x<array->NX);
    assert(y<array->NY);
    assert(z<array->NZ);
    return array->data[x*NY*NZ+y*NZ+z];
}
void intArray3dSet(intArray3d* array, int x, int y, int z, int value) {
    assert(x<array->NX);
    assert(y<array->NY);
    assert(z<array->NZ);
    array->data[x*NY*NZ+y*NZ+z] = value;
}

Notably:

  • This avoids unnecessary allocations. The metadata and all of the data happens in a single allocation.
  • It's super easy to allocate and free.
  • This tracks the various dimensions alongside the data.
  • Nobody is going to see a int*** and wonder how big each dimension is. The data already knows.
  • It's very easy to use correctly.
Mooing Duck
  • 64,318
  • 19
  • 100
  • 158