1

I am trying to shift the elements in a dynamically created 3d array by one index, so that each element [i][j][k] should be on [i+1][j][k].

This is how my array creation looks like

typedef struct stencil{
int ***arr;
int l;
int m;
int n;}matrix;

void createMatrix(matrix *vector){

vector->arr = (int***) malloc(sizeof(int**) * (vector->l+2));
for (int i = 0; i< vector->l+2; ++i) {
    vector->arr[i] = (int**) malloc(sizeof(int*) * (vector->m+2));
    for (int j = 0; j < vector->m+2; ++j) {
        vector->arr[i][j] = (int*) calloc((vector->n+2),sizeof(int));
    }

}
}

This is basically what I want to achieve with memmove

for(int i = vector->l-1; i >= 0; --i){
    for(int j = vector->m; j >= 0; --j){
        for(int k = vector->n; k >= 0; --k){
            vector->arr[i+1][j][k] = vector->arr[i][j][k];
        }
    }
}

for some reason memmove shifts 2 indices.

memmove(&(vector->arr[1][1][1]), &(vector->arr[0][1][1]), (vector->l+2)*(vector->m+2)*(vector->n)*sizeof(int*));

Could anyone give me a hint?

Schueni1
  • 13
  • 4
  • 1
    You need to post a [minimal, complete, and verifiable example](https://stackoverflow.com/help/mcve) see we can see what you're working with. There are many ways that you could implement `vector`. – user3386109 Dec 26 '17 at 21:49
  • If it's dynamically-allocated, the first dimension should be an array of pointers. Why don't just just shift those pointers, instead of moving all the data? – Barmar Dec 26 '17 at 22:26

3 Answers3

2

When you create a dynamic multi-dimensional array like this, the array contents are not contiguous -- each row is a separate allocation. So you can't move it all with a single memmov().

But you don't need to copy all the data, just shift the pointers in the top-level array.

int **temp = arr[l-1]; // save last pointer, which will be overwritten
memmov(&arr[1], &arr[0], sizeof(*arr[1]));
arr[0] = temp;

I've shifted the last element around to the first, to avoid having two elements that point to the same data. You could also free the old last element (including freeing the arrays it points to) and create a new first element, but this was simpler.

Barmar
  • 741,623
  • 53
  • 500
  • 612
1

Simply doing this would work (Illustrating in a 3d array)

memmove(arr[1], arr[0], Y*Z*sizeof(int));

where Y and Z denotes the other 2 dimensions of the 2d array.

Here arr[X][Y][Z] is the int array where X>=2.

In case of dynamically allocated memory you need to do each continuous chunk one by one. Then it would work.

user2736738
  • 30,591
  • 5
  • 42
  • 56
1

Compile with a higher optimization level (-O3). Obtain a direct reference on vector->arr instead of forcing dereferencing on every single array access.

Your call to memmove looks half correct under the assumption that you allocated arr as continuous memory. However, since you said "dynamic", I very much doubt that. Plus the size calculation appears very much wrong, with the sizeof(int*).

I suppose arr is not int arr[constexpr][constexpr][constexpr] (single, continuous allocation), but rather int ***arr.

In which case the memmove goes horribly wrong. After moving the int** contents of the arr field by one (which actually already did the move), it caused a nasty overflow on the heap, most likely by chance hitting also a majority of the int* allocations following.

Looks like a double move, and leaves behind a completely destroyed heap.

Ext3h
  • 5,713
  • 17
  • 43