Search code examples
cpointersmemcpy

memcpy a 3d pointer in c


How can I memcpy a 3d pointer to another 3d? I already tried the following:

void somefunction(ArrayBlock **** b1, int noOfBlocks, ArrayBlock **** b2){  
   memcpy((&b2), (&b1), noOfBlocks*sizeof(ArrayBlock));
}

This gives me the following error in gdb:

[Inferior 1 (process 8528) exited with code 030000000005]

both b1 and b2 were allocated memory in the main function like this:

ArrayBlock ***b2;
b2 = malloc(max_x * sizeof(ArrayBlock **));
for (i = 0; i < max_x; ++i)                             
{
    b2[i] = malloc(max_y * sizeof(ArrayBlock *));
    for (j = 0; j < max_y; ++j)
    {
        b2[i][j] = malloc(max_z* sizeof(ArrayBlock));
    }
}


Solution:

I figured that because the initialization of my 3D pointer (array) was non-contiguous, one memcpy will not be enough.

so this is what I did:

int i2, j2;
for(i2 = 0; i2 < max_x; i2++){
  for(j2 = 0; j2 < max_y; j2++){
    memcpy(&(*b2)[i2][j2][0], &(*b1)[i2][j2][0], max_z*sizeof(ArrayBlock));
  }
}

I think this time it works for real, thanks to those who helped me.


Solution

  • That depends how your 3D array was allocated, but in the most common case (array of arrays of arrays) the answer is no.

    There is a way to allocate a 3D array in such way that it's possible, however:

    • Allocate a single CX*CY*CZ array of Stuffs (Stuff* pXyz)
    • Allocate a single CX*CY array of pointers to Stuff (Stuff** ppXy)
    • Initialize it with pointers to various areas of pXyz (ppXy[x*CY + y] = &pXyz[x*CY*CZ + y*CZ + 0];)
    • Allocate a single CX array of pointers to pointers to Stuff (Stuff*** pppX)
    • Initialize it with pointers to various areas of ppXy (pppX[x] = &ppXy[x*CY + 0];)
    • return pppX;

    I hope I didn't get these wrong, but it's the base idea: One dimension, one malloc.

    Stuff*** Alloc3DArray(size_t cx, size_t cy, size_t cz) {
        Stuff*** ret = NULL;
    
        /*Allocate a single CX*CY*CZ array of Stuffs*/
        Stuff* pXyz = malloc(cx * cy * cz * sizeof(*pXyz));
        if(pXyz!=NULL) {
            /*Allocate a single CX*CY array of pointers to Stuff*/
            Stuff** ppXy = malloc(cx * cy * sizeof(*ppXy));
            if(ppXy!=NULL) {
                /*Allocate a single CX array of pointers to pointers to Stuff*/
                Stuff*** pppX = malloc(cx * sizeof(*pppX));
                if(pppX!=NULL) {
    
                    /*Initialize ppXy with pointers to various areas of pXyz*/
                    size_t x, y;
                    for(x=0 ; x<cx ; x++){
                        for(y=0 ; y<cy ; y++){
                            ppXy[x*cy + y] = &pXyz[x*cy*cz + y*cz + 0];
                        }
                    }
    
                    /*Initialize pppX with pointers to various areas of ppXy*/
                    for(x=0 ; x<cx ; x++){
                        pppX[x] = &ppXy[x*cy + 0];
                    }
    
                    /*Success!*/
                    ret = pppX;
                } else {
                    /*Allocating third level failed: free first and second levels*/
                    free(ppXy), ppXy=NULL;
                    free(pXyz), pXyz=NULL;
                }
            } else {
                /*Allocating second level failed: free first level*/
                free(pXyz), pXyz=NULL;
            }
        }
        return ret;
    }
    

    With this, you can memcpy this:

    memcpy(&pppDest[0][0][0], &pppSource[0][0][0], CX*CY*CZ*sizeof(***pppDest));
    

    Added: And when you're done with the array, if you've done it right it can be freed thusly:

    void Free3DArray(Stuff ***pppArr) {
        if(pppArr != NULL) {
            free(**pppArr); /*Free third level*/
            free( *pppArr); /*Free second level*/
            free(  pppArr); /*Free first level*/
        }
    }