Шматмерныя масівы, выдзеленыя праз calloc

У мяне ёсць пытанне аб тым, як памяць вылучаецца пры I calloc . Я меў погляд на гэта пытанне, але гэта Абыякава » т вырашыць, як памяць вылучаецца ў выпадку дынамічна размеркавальнай двухмернага масіва.

Мне было цікава, калі ёсць розніца ў прадстаўленні памяці паміж наступнымі трыма спосабамі дынамічнага размеркавання 2D-масіў.

<�Моцны> Тып 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]

<�Моцны> Тып 2:

double  **array1;
int ii;

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

<�Моцны> Тып 3:

double  **array1;
int ii;

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

З таго, што я разумею з calloc і Таноса , розніца паміж двума апошнімі ў тым, што calloc абнуліць ўсе элементы масіва, у той час як < код> Таноса не будзе. Але першыя два спосабу вызначэння эквівалента масіва ў памяці?

9
@Dancrumb О, вядома, не думаў пра гэта. Добрае пытанне.
дададзена аўтар JBL, крыніца
@Dancrumb О, вядома, не думаў пра гэта. Добрае пытанне.
дададзена аўтар JBL, крыніца
Тып 2 і тып 3, у асноўным тое ж самае, за выключэннем памяці будзе ўстаноўлена значэнне 0 з кодам <> calloc . Не ведаю, ці ёсць рэальная розніца з 1 тыпам, хоць.
дададзена аўтар JBL, крыніца
@JBL: сапраўды толькі дадатковае месца для паказальнікаў і той факт, што блокі 10 дубляў могуць у канчатковым выніку несумежных
дададзена аўтар Dancrumb, крыніца
@JBL: сапраўды толькі дадатковае месца для паказальнікаў і той факт, што блокі 10 дубляў могуць у канчатковым выніку несумежных
дададзена аўтар Dancrumb, крыніца
@alk - Не ... пытанне, які я звязаны толькі тлумачыць, як двухмерныя статычныя масівы захоўваюцца. Гэта не кажа пра дынамічна выдзеленых масіваў. Я б сцвярджаць, што гэта бясплатны пытанне, а не дублікат.
дададзена аўтар Kitchi, крыніца
<�Код> Таноса не вылучае 2D масіў. Ён вылучае неапрацаваны кавалак памяці (1D-масіў сімвалаў). Тое, што вы з ім рабіць не Таноса 's адказнасць.
дададзена аўтар n.m., крыніца
<�Код> Таноса не вылучае 2D масіў. Ён вылучае неапрацаваны кавалак памяці (1D-масіў сімвалаў). Тое, што вы з ім рабіць не Таноса 's адказнасць.
дададзена аўтар n.m., крыніца
дададзена аўтар alk, крыніца
Кампаноўка такая ж, для статычнага або дынамічнага размеркавання, па меншай меры, калі апошні выкарыстоўвае правільнае аб'яву зменнай для вылучэння памяці, каб, як і ў «адзін стрэл» падыход: двайны (* doubles2d) [N], [ М] = Таноса (N * M * SizeOf (двайны));
дададзена аўтар alk, крыніца
Кампаноўка такая ж, для статычнага або дынамічнага размеркавання, па меншай меры, калі апошні выкарыстоўвае правільнае аб'яву зменнай для вылучэння памяці, каб, як і ў «адзін стрэл» падыход: двайны (* doubles2d) [N], [ М] = Таноса (N * M * SizeOf (двайны));
дададзена аўтар alk, крыніца
Адказы на пытанне, які вы звязаны кажа ўсё гэта.
дададзена аўтар alk, крыніца
Адказы на пытанне, які вы звязаны кажа ўсё гэта.
дададзена аўтар alk, крыніца
Выпадкі 2 і 3 не вылучаюць дубляў наогул.
дададзена аўтар alk, крыніца
Выпадкі 2 і 3 не вылучаюць дубляў наогул.
дададзена аўтар alk, крыніца
дададзена аўтар alk, крыніца

8 адказы

<�Р> Ці сапраўды першыя два спосабу вызначэння эквівалент масіва ў памяці?

Не зусім. У другім тыпе яны амаль напэўна датыкаюцца, у той час як у першым тыпе, гэта не дакладна.

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| | |
          +---+
3
дададзена
<�Р> Ці сапраўды першыя два спосабу вызначэння эквівалент масіва ў памяці?

Не зусім. У другім тыпе яны амаль напэўна датыкаюцца, у той час як у першым тыпе, гэта не дакладна.

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| | |
          +---+
3
дададзена

просты прыклад

#include
#include

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;
}
1
дададзена

просты прыклад

#include
#include

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;
}
1
дададзена

У выпадку 1, вы робіце:

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

Заўвага: Вы не можаце выказаць здагадку, што вобласць памяці бесперапынна, могуць існаваць прабелы.

У выпадку 2 вы робіце:

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.

1
дададзена
Вы ведаеце, што выпадкі 2 і 3 не вылучаюць ніякіх дубляў на ўсіх, а толькі паказальнікі на іх, вы?
дададзена аўтар alk, крыніца
Выпадкі 2 і 3 выкарыстання менш або роўная памяць, то ў першую чаргу.
дададзена аўтар alk, крыніца
Ну яны абодва надаць аднаму памяці (не двайны памяці ці двайны * памяці, яго проста памяць!), І з 64-бітнай машыне SizeOf (двайны *) == SizeOf (двайны) == 8, а на 32-бітнай машыне SizeOf (двайны *) = = 4, у той час як SizeOf (двайны) == 8. Так што так, вы маеце рацыю, выпадкі 2 і 3 на прыкладзе кода абодва маюць рацыі, яны павінны вылучаць элементы памяці памерам двайны, а не ў два разы *.
дададзена аўтар susundberg, крыніца
Вы абсалютна правы. Тое, што я спрабаваў растлумачыць на апошнім пункце з нумарамі, але быў «памылка друку», кажучы «другі», як гэта было выказаць здагадку, каб быць «першым». Я рэдагаваў пост для гэтага.
дададзена аўтар susundberg, крыніца

У выпадку 1, вы робіце:

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

Заўвага: Вы не можаце выказаць здагадку, што вобласць памяці бесперапынна, могуць існаваць прабелы.

У выпадку 2 вы робіце:

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.

1
дададзена
Вы ведаеце, што выпадкі 2 і 3 не вылучаюць ніякіх дубляў на ўсіх, а толькі паказальнікі на іх, вы?
дададзена аўтар alk, крыніца
Выпадкі 2 і 3 выкарыстання менш або роўная памяць, то ў першую чаргу.
дададзена аўтар alk, крыніца
Ну яны абодва надаць аднаму памяці (не двайны памяці ці двайны * памяці, яго проста памяць!), І з 64-бітнай машыне SizeOf (двайны *) == SizeOf (двайны) == 8, а на 32-бітнай машыне SizeOf (двайны *) = = 4, у той час як SizeOf (двайны) == 8. Так што так, вы маеце рацыю, выпадкі 2 і 3 на прыкладзе кода абодва маюць рацыі, яны павінны вылучаць элементы памяці памерам двайны, а не ў два разы *.
дададзена аўтар susundberg, крыніца
Вы абсалютна правы. Тое, што я спрабаваў растлумачыць на апошнім пункце з нумарамі, але быў «памылка друку», кажучы «другі», як гэта было выказаць здагадку, каб быць «першым». Я рэдагаваў пост для гэтага.
дададзена аўтар susundberg, крыніца

У першым спосабе, вы размяркоўваеце 10 паказальнікаў на двайны, і 100 двухмесных. У другім выпадку вы вылучыць 100 паказальнікаў на double.The іншага адрозненне заключаецца ў тым, што ў другім шляху, вы вылучаеце адзін вялікі блок памяці, так што ўсе элементы вашага масіва знаходзяцца ў адным блоку. У першым спосабе, кожная «радок» з вашага масіва знаходзіцца ў іншым блоку, чым іншыя. Хоць, у другім шляху, ваш масіў павінен быць падвойным * замест двайны **, таму што ў гэтым выпадку вылучэння, ваш масіў ўтрымлівае толькі паказальнікі на два раз, а не ў два разы.

1
дададзена
Першыя два спосабу не выкарыстоўваюць адзін і той жа аб'ём памяці. Першы метад выкарыстоўвае дзесяць разоў роднага памеру паказальніка больш.
дададзена аўтар Dancrumb, крыніца
Пад рэдакцыяй паправак.
дададзена аўтар Marrow Gnawer, крыніца
Першы спосаб: 10 паказальнікаў, 100 двойчы, другі метаду: 100 паказальнікаў, ня падвойнае, ды не тое ж самае колькасць маіх дрэннае. Але другі метад яшчэ не мае двайны выдзелена.
дададзена аўтар Marrow Gnawer, крыніца

У першым спосабе, вы размяркоўваеце 10 паказальнікаў на двайны, і 100 двухмесных. У другім выпадку вы вылучыць 100 паказальнікаў на double.The іншага адрозненне заключаецца ў тым, што ў другім шляху, вы вылучаеце адзін вялікі блок памяці, так што ўсе элементы вашага масіва знаходзяцца ў адным блоку. У першым спосабе, кожная «радок» з вашага масіва знаходзіцца ў іншым блоку, чым іншыя. Хоць, у другім шляху, ваш масіў павінен быць падвойным * замест двайны **, таму што ў гэтым выпадку вылучэння, ваш масіў ўтрымлівае толькі паказальнікі на два раз, а не ў два разы.

1
дададзена
Першыя два спосабу не выкарыстоўваюць адзін і той жа аб'ём памяці. Першы метад выкарыстоўвае дзесяць разоў роднага памеру паказальніка больш.
дададзена аўтар Dancrumb, крыніца
Пад рэдакцыяй паправак.
дададзена аўтар Marrow Gnawer, крыніца
Першы спосаб: 10 паказальнікаў, 100 двойчы, другі метаду: 100 паказальнікаў, ня падвойнае, ды не тое ж самае колькасць маіх дрэннае. Але другі метад яшчэ не мае двайны выдзелена.
дададзена аўтар Marrow Gnawer, крыніца