Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access 1D arrays with multiple brackets for readability?

I have a huge code using a 3D array managed with pointers. Something like:

int *** tab;
tab = malloc(m*sizeof(int**));
for(i= 1..n) tab[i] = malloc(n*sizeof(int*));  
... etc...

and later the elements are accessed with:

tab[i][j][k] = ...

But because of specific issues with this structure, I would like to declare tab as a contiguous array instead but still use the syntax with 3 brackets in the code. The compiler will internally replace them like this:

tab[i][j][k] = ...  =>  tab[i*m*n+j*m+k] = ...

So the array is accessed with only one pointer dereference. I'd like not to change the source code (no sed).

For example I could do this by declaring tab in stack:

int tab[n][m][l];

but unfortunately this doesn't work if m and n are runtime variables.

like image 390
Saiph Avatar asked May 26 '16 14:05

Saiph


People also ask

How do you make a multidimensional array?

You can create a multidimensional array by creating a 2-D matrix first, and then extending it. For example, first define a 3-by-3 matrix as the first page in a 3-D array. Now add a second page. To do this, assign another 3-by-3 matrix to the index value 2 in the third dimension.

Do arrays use square brackets?

JavaScript arrays are a special type of object. To access an array item, the [] operator is used, for example colors[2] . The [] operator converts the expression inside the square brackets to a string.

How do you populate a one direction array?

You can use the ArraySet function to populate a 1D array, or one dimension of a multidimensional array, with some initial value, such as an empty string or zero. This can be useful to create an array of a certain size, without adding data to it right away.

Are 1D arrays faster than 2D?

Unless you are talking about static arrays, 1D is faster. Clearly the 2D case loses the cache locality and uses more memory. It also introduces an extra indirection (and thus an extra pointer to follow) but the first array has the overhead of calculating the indices so these even out more or less. Save this answer.


1 Answers

A C++ way is to enclose the 3D array in a class to have a natural accessor:

struct Arr3D
{
    int *arr;
    const int n, m, p; //size of the tab in 3 dimensions

public:
    Arr3D(int n, int m, int l): n(n), m(m), p(l) {
        arr = new int[n * m * p];
    }

    ~Arr3D() {
        delete[] arr;
    }

    int& val(int i, int j, int k) {   // read-write accessor
        // optionaly test for 0<=i<n...
        return arr[k + p * (j + i * m)];
    }
};

You create and use an array simply with:

Arr3D * parr = new Arr3D(3,4,5); // dynamic allocation
Arr3D arr(3, 4, 5);              // automatic allocation
...
arr(1,2,3) = 5;
int i = arr(2,0,1);

Alternatively, if you want to keep the syntax tab[i][j][k] you can if you use an auxilliary Arr2D class able to provide a view on a 2D array:

struct Arr2D
{
    int *arr;
    const int n, m; //size of the tab in 2 dimensions
    const bool is_view;

public:
    Arr2D(int n, int m): n(n), m(m), is_view(false) {
        arr = new int[n * m];
    }
    Arr2D(int *arr, int n, int m): arr(arr), n(n), m(m), is_view(true) {}

    ~Arr2D() {
        if (! is_view) delete[] arr;
    }

    int * operator[] (int i) {
        return arr + i * m;
    }
};

struct Arr3D
{
    int *arr;
    const int n, m, p; //size of the tab in 3 dimensions

public:
    Arr3D(int n, int m, int l): n(n), m(m), p(l) {
        arr = new int[n * m * p];
    }

    ~Arr3D() {
        delete[] arr;
    }

    Arr2D operator[](int i) {
        return Arr2D(arr + i * p * m, m, p);
    }
};

You can now simply use arr[i][j][k] ...

like image 163
Serge Ballesta Avatar answered Oct 17 '22 10:10

Serge Ballesta