14

I have a question about how memory is allocated when I calloc. I had a look at this question, but it doesn't address how memory is allocated in the case of a dynamically allocated two dimensional array.

I was wondering if there was a difference in the memory representation between the following three ways of dynamically allocating a 2D array.

Type 1:

double  **array1;
int ii;

array1 = calloc(10, sizeof(double *));
for(ii = 0; ii < 10; ii++) { 
   array1[ii] = calloc(10, sizeof(double));
}
// Then access array elements like array1[ii][jj]

Type 2:

double  **array1;
int ii;

array1 = calloc(10 * 10, sizeof(double *));
// Then access array elements like array1[ii + 10*jj]

Type 3:

double  **array1;
int ii;

array1 = malloc(10 * 10, sizeof(double *));
// Then access array elements like array1[ii + 10*jj]

From what I understand of calloc and malloc, the difference between the last two is that calloc will zero all the elements of the array, whereas malloc will not. But are the first two ways of defining the array equivalent in memory?

Community
  • 1
  • 1
Kitchi
  • 1,874
  • 4
  • 28
  • 46
  • Type 2 and Type 3 are basically the same thing, except memory will be set to 0 with `calloc`. Don't know if there's a real difference with Type 1 though. – JBL May 23 '13 at 13:49
  • @JBL: really just the additional space for the pointers and the fact that the blocks of 10 doubles may end up being noncontiguous – Dancrumb May 23 '13 at 13:54
  • @Dancrumb Oh indeed, didn't think of that. Good point. – JBL May 23 '13 at 13:56
  • Cases 2 and 3 do not allocate doubles at all. – alk May 23 '13 at 15:30
  • The answers to the question you linked says it all. – alk May 23 '13 at 15:33
  • 1
    possible duplicate of [How are multi-dimensional arrays formatted in memory?](http://stackoverflow.com/questions/2565039/how-are-multi-dimensional-arrays-formatted-in-memory) – alk May 23 '13 at 15:36
  • @alk - No... the question I linked to only explains how two dimensional static arrays are stored. It doesn't talk about dynamically allocated arrays. I'd argue that this is a complimentary question, rather than a duplicate. – Kitchi May 23 '13 at 15:46
  • The layout is the same, for static or dynamic allocation, at least if the latter uses the correct declaration of the variable to allocate memory to, like in the "one shot" approach: `double (*doubles2d)[N][M] = malloc(N*M*sizeof(double));` – alk May 23 '13 at 16:30
  • `malloc` doesn't allocate a 2D array. It allocates a raw chunk of memory (a 1D array of characters). What you do with it is not `malloc`'s responsibility. – n. m. could be an AI Oct 15 '15 at 19:31
  • The second and third examples should be sizeof(double) instead of sizeof(double *), the third example shouldn't have a comma in the malloc parameters, and if you're using the [ii + 10*jj]] form of referencing, array1 should only be of type double * – JustinB Apr 30 '19 at 00:04

4 Answers4

9

Are the first two ways of defining the array equivalent in memory?

Not quite. In the second type they are almost certainly contiguous, while in the first type this is not sure.

Type 1: in-memory representation will look like this:

          +---+---+---+---+---+---+---+---+---+---+
    double| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |   
          +---+---+---+---+---+---+---+---+---+---+ 
            ^
            |------------------------------------                                     
                .   .   .   .   .   .   .   .   |    // ten rows of doubles
                                                -
          +---+---+---+---+---+---+---+---+---+--|+
    double| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0||   
          +---+---+---+---+---+---+---+---+---+--|+
            ^   .   .   .                       -
            |   ^   ^   ^   .   .   .   .   .   |
            |   |   |   |   ^   ^   ^   ^   ^   |
          +-|-+-|-+-|-+-|-+-|-+-|-+-|-+-|-+-|-+-|-+
array1[ii]| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | // each cell points to ten doubles
          +---+---+---+---+---+---+---+---+---+---+
            ^
            |
            |
          +-|-+
    array1| | |
          +---+

Type 2: in-memory representation will look like this:

          +---+---+---+---+---+---+---+---+---+---+     +---+
    double| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 |  
          +---+---+---+---+---+---+---+---+---+---+     +---+
            ^   ^   ^   ^   ^   ^   ^   ^   ^   ^         ^
            |   |   |   |   |   |   |   |   |   |         |
            |   |   |   |   |   |   |   |   |   |         |
          +-|-+-|-+-|-+-|-+-|-+-|-+-|-+-|-+-|-+-|-+     +-|-+
array1[ii]| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ... |99 | // each cell points to one double
          +---+---+---+---+---+---+---+---+---+---+     +---+
            ^
            |
            |
          +-|-+
    array1| | |
          +---+
Ziezi
  • 6,375
  • 3
  • 39
  • 49
1

Simple Example

#include<stdio.h>
#include<stdlib.h>

int **d ;
int sum();

//----------------------------------------------  
int main(){

    d = (int **)calloc(3,sizeof(int*));
    printf("\n%d",sum());     
}

//-----------------------------------------------
int sum(){
   int s = 0;
   for(int i = 0; i < 3; i++)
       d[i] = (int *) calloc (3,sizeof(int));

   for(int i = 0; i < 3; i++){ 
       for(int j = 0; j < 3; j++){
           d[i][j] = i+j;
           s += d[i][j];
           printf("\n array[%d][%d]-> %d",i,j,d[i][j]);
        }
   }
   return s;
}
rsc
  • 10,348
  • 5
  • 39
  • 36
Monis Majeed
  • 1,358
  • 14
  • 21
0

In the first way, you allocate 10 pointers to double, and 100 double. In the second way you allocate 100 pointers to double.The other difference is that in the second way, you allocate one big block of memory, so that all the elements of your array are in the same block. In the first way, each "row" of your array is in a different block than the others. Though, in the second way, your array should be a double* instead of a double**, because in this way of allocating, your array only contains pointers to double, not double.

Waterfrag
  • 517
  • 4
  • 20
  • First two ways do not use the same amount of memory. The first method uses ten times the native size of a pointer more. – Dancrumb May 23 '13 at 14:00
  • First method : 10 pointers, 100 double, second method : 100 pointers, no double, yeah not same amount my bad. But the second method still has no double allocated. – Waterfrag May 23 '13 at 14:21
0

On the case 1, you make:

array1[0] -> [memory area of 10]
array1[1] -> [memory area of 10] ...
array1[N] -> [memory area of 10] ...

Note: You cannot assume that the memory area is continuous, there might be gaps.

On the case 2 you make:

array1 -> [memory area of 100]

The case 3 is same as the case 2, but its not initializing the memory. Difference between case 1 and 2 & 3 is that on the first case you really have 2D memory structure. For example if you want to swap rows 1 and 2, you could just swap the pointers:

help      = array1[1] 
array1[1] = array1[2] 
array1[2] = help

But if you want to do the same in the 2&3 case you need to do real memcpy. What to use? Depends what you are doing.

The first way uses bit more memory: if you would have array of 1000x10 then the first version will use 1000*8 + 1000*10*8 (on 64bit system), while the 2&3 will only use 1000*10*8.

susundberg
  • 650
  • 7
  • 14
  • The cases 2 and 3 use less or equal memory then the first. – alk May 23 '13 at 15:31
  • You are absolutely correct. Thats what i tried to explain on the last paragraph with the numbers, but had 'typo' saying 'second' as it was suppose to be 'first'. I edited the post for this. – susundberg May 24 '13 at 06:19
  • You are aware that cases 2 and 3 do not allocate any doubles at all, but only pointers to those, are you? – alk May 24 '13 at 06:58
  • Well they both allocate chunk of memory (not double memory or double* memory, its just memory!) , and with 64bit machine sizeof(double*) == sizeof(double) == 8 but on 32bit machine sizeof(double*) == 4, while sizeof(double) == 8. So yes, you are correct, the cases 2&3 on the example code are both wrong, they should allocate memory elements of size double, not double*. – susundberg May 24 '13 at 11:47