Thread: 4-dimensional array contiguous allocation

  1. #1
    Registered User
    Join Date
    Feb 2005
    Posts
    7

    4-dimensional array contiguous allocation

    Hi all,
    I was wondering if anyone could help me to allocate a 4-dimensional array as a contiguous block of memory. I've figured out how to do this for the 3-dimensional case (see code below), but am having trouble extending to 4-d. Pointer aritmetic is not my forte!
    Thanks!

    Code:
    //matrix size is x*y*z
      double ***bigMatrix;
      bigMatrix = (double***) malloc(x*sizeof(double**));
      bigMatrix[0] = (double**)malloc(x*y*sizeof(double*));
      bigMatrix[0][0] = (double*)malloc(x*y*z*sizeof(double));
    
      for(j=1; j<y; j++) 
        bigMatrix[0][j]=bigMatrix[0][j-1]+z;
       for(i=1; i<x; i++){
        bigMatrix[i]=bigMatrix[i-1]+y;
        bigMatrix[i][0]=bigMatrix[i-1][0]+y*z;
        for(j=1; j<y; j++){
          bigMatrix[i][j]=bigMatrix[i][j-1]+x; 
        }
       }
    Last edited by ShaunMahony; 02-08-2005 at 03:51 PM.

  2. #2
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    That is not guaranteed to create the array in contiguous memory. Subsequent calls to malloc() don't necessarily have to allocate memory right up against or even near previous allocations.

    And aren't you increasing the size backwards? The only way to really do it is in one malloc() call, or one malloc() call followed by realloc() calls.

    Code:
    Something like: ptr = malloc(dim1_size * dim2_size * dim3_size * dim4_size * element_size);
    If you understand what you're doing, you're not learning anything.

  3. #3
    Registered User
    Join Date
    Feb 2005
    Posts
    7
    Hey itsme86,
    This is a contiguous allocation; there is only one malloc call where doubles are actually allocated. The other malloc calls are there to set up the pointers so that the notation "bigMatrix[i][j][k][l]" can be used. Referencing bigMatrix[0][0] will allow access to a contiguous block of x*y*z doubles.
    Trust me, it works :-)
    Your code will only allow the notation "ptr[i]"
    Shaun

  4. #4
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    I have no doubt that your code works, but what you have is a contiguous array of a contiguous array of a contiguous array of doubles. That is not the same thing as a contiguous 3-dimensional array.
    If you understand what you're doing, you're not learning anything.

  5. #5
    Registered User
    Join Date
    Feb 2005
    Posts
    7
    Okay, well we won't argue over semantics, but it remains that there is a single call where a block of doubles is allocated contiguously. The pointers can indeed be seen as separate arrays if you want, but they don't contain the data; they set up the indexing structure. The actually data is lined up together in memory.
    As I said, we won't argue, as this isn't getting my question answered

  6. #6

    4-dimensional allocation

    Hello,

    Pointers are my forte. So maybe I can help. I've always liked dealing with multi-dimensional arrays. Though, I've never actually tested pointer allocation. Today, I have. The following is an example, that should help you learn the general concept:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    /*
    Our example.
    
    int arr[2][2][3][4] = {
        {
            { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} },
            { {12, 13, 14, 15}, {16, 17, 18, 19}, {20, 21, 22, 23} },
        },
        {
            { {24, 25, 26, 27}, {28, 29, 30, 31}, {32, 33, 34, 35} },
            { {36, 37, 38, 39}, {40, 41, 42, 43}, {44, 45, 46, 47} },
        }
    };
    */
    
    int main() {
        /* Local variables */
        int i=0, j=0, k=0, l=0, f, m=0;
        int ****arr = NULL;
    
        /* arr[2] */
        arr = malloc(2 * sizeof *arr);
        if (arr) {
            /* arr[2][2] */
            for (i = 0; i < 2; i++) {
                /* Allocate memory */
                arr[i] = malloc(2 * sizeof *arr);
    
                /* If allocation failed */
                if (arr[i] == NULL) {
                        /* Free any memory that was previously used */
                        for (f = i; f >= 0; f--) {
                            if (arr[f] != NULL) {
                                free(arr[f]);
                                arr[f] = NULL;
                            }
                        }
                        /* Free any memory that was previously used from beginning */
                        if (arr != NULL) {
                            free(arr);
                            arr = NULL;
                        }
    
                        /* Terminate program */
                        return 0;
                }
    
                /* arr[2][2][3] */
                for (j = 0; j < 2; j++) {
                    /* Allocate memory */
                    arr[i][j] = malloc(3 * sizeof *arr);
    
                    /* If allocation failed */
                    if (arr[i][j] == NULL) {
                        /* Free any memory that was previously used */
                        for (f = j; f >= 0; f--) {
                            if (arr[i][f] != NULL) {
                                free(arr[i][f]);
                                arr[i][f] = NULL;
                            }
                        }
                        /* Free any memory that was previously used in previous loop */
                        for (f = i; f >= 0; f--) {
                            if (arr[f] != NULL) {
                                free(arr[f]);
                                arr[f] = NULL;
                            }
                        }
                        /* Free any memory that was previously used from beginning */
                        if (arr != NULL) {
                            free(arr);
                            arr = NULL;
                        }
    
                        /* Terminate program */
                        return 0;
                    }
    
                    /* arr[2][2][3][4] */
                    for (k = 0; k < 3; k++) {
                        /* Allocate memory */
                        arr[i][j][k] = malloc(4 * sizeof *arr);
    
                        /* If allocation failed */
                        if (arr[i][j][k] == NULL) {
                            /* Free any memory that was previously used */
                            for (f = k; f >= 0; f--) {
                                if (arr[i][j][f] != NULL) {
                                    free(arr[i][j][f]);
                                    arr[i][j][f] = NULL;
                                }
                            }
                            /* Free any memory that was previously used */
                            for (f = j; f >= 0; f--) {
                                if (arr[i][f] != NULL) {
                                    free(arr[i][f]);
                                    arr[i][f] = NULL;
                                }
                            }
                            /* Free any memory that was previously used in previous loop */
                            for (f = i; f >= 0; f--) {
                                if (arr[f] != NULL) {
                                    free(arr[f]);
                                    arr[f] = NULL;
                                }
                            }
                            /* Free any memory that was previously used from beginning */
                            if (arr != NULL) {
                                free(arr);
                                arr = NULL;
                            }
    
                            /* Terminate program */
                            return 0;
                        }
                    }
                }
            }
        }else {
            return 0;
        }
    
        /* Make sure we can write without failure */
        for (i = 0; i < 2; i++) {
            for (j = 0; j < 2; j++) {
                for (k = 0; k < 3; k++) {
                    for (l = 0; l < 4; l++) {
                        arr[i][j][k][l] = m++;
                    }
                }
            }
        }
    
        /* Print array style for example sake */
        printf("In example to: int arr[2][2][3][4];\n\n");
        printf("int ****arr = {\n");
        printf("\t{\n");
        printf("\t\t{ {%d, %d, %d, %d}, {%d, %d, %d, %d}, {%d, %d, %d, %d} },\n", arr[0][0][0][0], 
            arr[0][0][0][1], arr[0][0][0][2], arr[0][0][0][3], arr[0][0][1][0], arr[0][0][1][1], 
            arr[0][0][1][2], arr[0][0][1][3], arr[0][0][2][0], arr[0][0][2][1], arr[0][0][2][2], 
            arr[0][0][2][3]);
        printf("\t\t{ {%d, %d, %d, %d}, {%d, %d, %d, %d}, {%d, %d, %d, %d} },\n", arr[0][1][0][0], 
            arr[0][1][0][1], arr[0][1][0][2], arr[0][1][0][3], arr[0][1][1][0], arr[0][1][1][1], 
            arr[0][1][1][2], arr[0][1][1][3], arr[0][1][2][0], arr[0][1][2][1], arr[0][1][2][2], 
            arr[0][1][2][3]);
        printf("\t},\n");
        printf("\t\t{ {%d, %d, %d, %d}, {%d, %d, %d, %d}, {%d, %d, %d, %d} },\n", arr[1][0][0][0], 
            arr[1][0][0][1], arr[1][0][0][2], arr[1][0][0][3], arr[1][0][1][0], arr[1][0][1][1], 
            arr[1][0][1][2], arr[1][0][1][3], arr[1][0][2][0], arr[1][0][2][1], arr[1][0][2][2], 
            arr[1][0][2][3]);
        printf("\t\t{ {%d, %d, %d, %d}, {%d, %d, %d, %d}, {%d, %d, %d, %d} },\n", arr[1][1][0][0], 
            arr[1][1][0][1], arr[1][1][0][2], arr[1][1][0][3], arr[1][1][1][0], arr[1][1][1][1], 
            arr[1][1][1][2], arr[0][0][1][3], arr[1][1][2][0], arr[1][1][2][1], arr[1][1][2][2], 
            arr[1][1][2][3]);
        printf("\t}\n};");
    
        /* Free Memory */
        for (i = 0; i < 2; i++) {
            for (j = 0; j < 2; j++) {
                for (k = 0; k < 3; k++) {
                    free(arr[i][j][k]);
                    arr[i][j][k] = NULL;
                }
                free(arr[i][j]);
                arr[i][j] = NULL;
            }
            free(arr[i]);
            arr[i] = NULL;
        }
        free(arr);
        arr = NULL;
    
        return 0;
    }
    Code 1.1: Allocating 4-dimensional pointer

    Hope this helps. I added comments to the code. If you have any questions, please feel free to ask.


    - Stack Overflow
    Last edited by Stack Overflow; 02-08-2005 at 04:12 PM. Reason: Fixed code
    Segmentation Fault: I am an error in which a running program attempts to access memory not allocated to it and core dumps with a segmentation violation error. This is often caused by improper usage of pointers, attempts to access a non-existent or read-only physical memory address, re-use of memory if freed within the same scope, de-referencing a null pointer, or (in C) inadvertently using a non-pointer variable as a pointer.

  7. #7
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    Well, here's one way you could do it:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(void)
    {
      int w = 5, x = 7, y = 10, z = 8;
      int ****array;
      int i, j, k;
    
      array = malloc(sizeof(double ***) * w);
    
      for(i = 0;i < w;++i)
      {
        array[i] = malloc(sizeof(double **) * x);
    
        for(j = 0;j < x;++j)
        {
          array[i][j] = malloc(sizeof(double *) * y);
    
          for(k = 0;k < y;++k)
            array[i][j][k] = malloc(sizeof(double) * z);
        }
      }
    
      // rest of code goes here. Don't forget to free every single allocation.
    
      return 0;
    }
    If you understand what you're doing, you're not learning anything.

  8. #8
    Registered User
    Join Date
    Feb 2005
    Posts
    7
    Hey Stack Overflow:
    That looks really good; thanks a million!
    One question though; is the data gauranteed to be contiguous. I'm not familiar with the notation you used in the malloc calls. What does "sizeof *arr" return? I'm guessing it will be a pointer to the currently located array, and I can kinda see how this is working. Where is the actual dataspace being allocated though? In the call "arr[i][j][k] = malloc(4 * sizeof* arr);", is the *arr actually representing the data type? If so, I guess that that's the only place where something equivalent to malloc(v*x*y*z*sizeof(int)) is called. Just confirm that this is your understanding also.
    If I've understood correctly, then this is a really niftly piece of code, and a pretty intuitive way to do what I wanted to do. Cheers!

  9. #9
    Registered User
    Join Date
    Feb 2005
    Posts
    7
    itsme86: you have "y" calls to malloc(sizeof(double) * z);, and therefore your data is not guaranteed to be contiguous.

  10. #10
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    Well I'm still not clear on which parts of the array you want to be contiguous. I don't only have "y" calls to malloc(sizeof(double) * z);. Don't forget that it's in a nested loop so there's actually w*x*y calls to it, which means that the array can hold w*x*y*z doubles, which is what I thought you were looking for.
    If you understand what you're doing, you're not learning anything.

  11. #11
    Registered User
    Join Date
    Feb 2005
    Posts
    7
    Oh, actually Stack Overflow, I read through your code wrong. Your code won't give contiguous dataspace at all. I wonder can I use that code to allocate pointers to an already allocated memory space. What would happen if I call arr[0][0][0] = (int*)malloc(2*2*3*4*sizeof(int)); at some point, after using your code to set up the indices?

  12. #12
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,005
    Quote Originally Posted by itsme86
    Well I'm still not clear on which parts of the array you want to be contiguous. I don't only have "y" calls to malloc(sizeof(double) * z);. Don't forget that it's in a nested loop so there's actually w*x*y calls to it, which means that the array can hold w*x*y*z doubles, which is what I thought you were looking for.
    To me it looks like ShaunMahony is trying to extend the "contiguous" example described here, which has a two-dimensional version done like this.
    You can keep the array's contents contiguous, while making later reallocation of individual rows difficult, with a bit of explicit pointer arithmetic:
    Code:
        int **array2 = (int **)malloc(nrows * sizeof(int *));
        array2[0] = (int *)malloc(nrows * ncolumns * sizeof(int));
        for(i = 1; i < nrows; i++)
            array2[i] = array2[0] + i * ncolumns;
    In either case, the elements of the dynamic array can be accessed with normal-looking array subscripts: arrayx[i][j] (for 0 <= i < NROWS and 0 <= j < NCOLUMNS).
    Last edited by Dave_Sinkula; 02-08-2005 at 05:21 PM. Reason: You miss a little word like 'is'...
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

  13. #13
    Hello,

    » One question though; is the data gauranteed to be contiguous.
    Well, I'm not exactly sure what you are referring too. C provides calloc() ("contiguous allocation") and malloc() ("memory allocation") in the standard library for dynamic memory allocation. For example:
    Code:
    #include <stdlib.h>
    
    int main() {
        int *a = NULL, n = 5;
    
        a = calloc(n, sizeof(int)); /* get space for n ints */
        /* is equivilent to: */
        /* a = malloc(n * sizeof(int)); */
    
        free(a);
    
        return 0;
    }
    Looking at Dave_Sinkula's post, I think I understand now. The way things look, my code isn't contiguous.

    » What does "sizeof *arr" return?
    Quite simple. sizeof(int) returns the size of an integer on the machine. My malloc functions as it sends what arr is pointing to, which is an int.

    » Where is the actual dataspace being allocated though?
    Simply. This is how my concept works.
    • Allocate arr[i] as i represents arr[2][2][3][4]
    • If allocation succeeds; Loop twice (i < 2) to allocate arr[i][j] as j represents arr[2][2][3][4]
    • Per loop (which loops twice) loop 2 times (j < 2) to allocate arr[i][j][k] as k represents arr[2][2][3][4]
    • Per loop inside i and j loop 3 times (k < 3) to allocate arr[i][j][k][l] as l represents arr[2][2][3][[b]4/b]]
    It may seem a bit complicated, but the idea is a logical one to me.


    - Stack Overflow
    Last edited by Stack Overflow; 02-08-2005 at 05:43 PM.
    Segmentation Fault: I am an error in which a running program attempts to access memory not allocated to it and core dumps with a segmentation violation error. This is often caused by improper usage of pointers, attempts to access a non-existent or read-only physical memory address, re-use of memory if freed within the same scope, de-referencing a null pointer, or (in C) inadvertently using a non-pointer variable as a pointer.

  14. #14
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    Is this what you're after?

    bar is the simple case, which should be easy to understand, and shows how the process starts.
    foo is the expanded to 4D case.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    void *my_malloc ( char *expr, size_t size ) {
        void *result = malloc( size );
        printf( "Malloc(%s) is size %lu, returning %p\n", expr, (unsigned long)size, result );
        return result;
    }
    void my_free( void *ptr ) {
        printf( "Free(%p)\n", ptr );
        free( ptr );
    }
    #define MY_MALLOC(x)    my_malloc( #x, x )
    #define MY_FREE(x)      my_free(x)
    
    
    /* create int [x][y] */
    int **create_a_bar ( int max_x, int max_y ) {
        int **all_x = MY_MALLOC( max_x * sizeof *all_x );
        int  *all_y = MY_MALLOC( max_x * max_y * sizeof *all_y );
        int **result = all_x;
        int x;
    
        for ( x = 0 ; x < max_x ; x++, all_y += max_y ) {
            result[x] = all_y;
        }
        
        return result;
    }
    
    /* create int [x][y][r][c] */
    int ****create_a_foo ( int max_x, int max_y, int max_r, int max_c ) {
        int ****all_x = MY_MALLOC( max_x * sizeof *all_x );
        int  ***all_y = MY_MALLOC( max_x * max_y * sizeof *all_y );
        int   **all_r = MY_MALLOC( max_x * max_y * max_r * sizeof *all_r );
        int    *all_c = MY_MALLOC( max_x * max_y * max_r * max_c * sizeof *all_c );
        int ****result = all_x;
        int x, y, r;
    
        for ( x = 0 ; x < max_x ; x++, all_y += max_y ) {
            result[x] = all_y;
            for ( y = 0 ; y < max_y ; y++, all_r += max_r ) {
                result[x][y] = all_r;
                for ( r = 0 ; r < max_r ; r++, all_c += max_c ) {
                    result[x][y][r] = all_c;
                }
            }
        }
    
        return result;
    }
    
    int main ( ) {
        int ****foo;
        int **bar;
        int x,y;
    
        printf( "Creating bar(2,3)\n" );
        bar = create_a_bar(2,3);
        printf( "Creating foo(2,3,4,5)\n" );
        foo = create_a_foo(2,3,4,5);
    
        printf( "\nContiguous memory check\n" );
        for ( x = 0 ; x < 2 ; x++ ) {
            for ( y = 0 ; y < 3 ; y++ ) {
                printf( "%p ", &bar[x][y] );
            }
            printf( "\n" );
        }
        printf( "\n" );
    
        printf( "Freeing bar\n" );
        MY_FREE( bar[0] );
        MY_FREE( bar );
        printf( "Freeing foo\n" );
        MY_FREE( foo[0][0][0] );
        MY_FREE( foo[0][0] );
        MY_FREE( foo[0] );
        MY_FREE( foo );
    
        return 0;
    }
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  15. #15
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    > Well, I'm not exactly sure what you are referring too. C provides calloc() ("contiguous allocation")
    calloc means cleared, not contiguous. calloc is just malloc and a memset - nothing more.

    Each call to malloc is guaranteed to return a pointer to a block of contiguous memory of the size specified, or NULL if there is a problem.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 16
    Last Post: 05-29-2009, 07:25 PM
  2. Dynamic Array Allocation function
    By P4R4N01D in forum C++ Programming
    Replies: 6
    Last Post: 05-15-2009, 02:04 AM
  3. pointer to array with dynamic allocation
    By cfdprogrammer in forum C Programming
    Replies: 22
    Last Post: 04-07-2009, 09:56 AM
  4. memory allocation for flexible array member of struct
    By jcarouth in forum C Programming
    Replies: 3
    Last Post: 09-11-2005, 12:19 PM
  5. 2d arrays in C
    By Unregistered in forum C Programming
    Replies: 6
    Last Post: 04-20-2002, 11:09 AM