문제

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?

도움이 되었습니까?

해결책

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| | |
          +---+

다른 팁

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;
}

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.

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.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top