Dynami c выделение памяти для 2d массива - PullRequest
0 голосов
/ 30 марта 2020

В этом коде, в то время как мы динамически распределяем память для 2D-массива, после 4-х адресов, почему он занимает промежуток в 16 байтов, но когда мы статически выделяем 2D-массив, у него нет такого разрыва .... что причина этого ???

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

int main() 
{ 
    int r = 3, c = 4, i, j, count; 

    int stat[r][c];

    int *arr[r]; 
    for (i=0; i<r; i++) 
         arr[i] = (int *)malloc(c * sizeof(int)); 

    // Note that arr[i][j] is same as *(*(arr+i)+j) 
    count = 0; 
    for (i = 0; i <  r; i++) 
      for (j = 0; j < c; j++) 
         arr[i][j] = ++count; // Or *(*(arr+i)+j) = ++count 

    for (i = 0; i <  r; i++) 
      for (j = 0; j < c; j++) 
         printf("%d\n", *(arr+i)+j); 

    printf("\n\n");  
    for (i = 0; i <  r; i++) 
      for (j = 0; j < c; j++) 
         printf("%d\n", *(stat+i)+j); 

    /* Code for further processing and free the  
      dynamically allocated memory */

   return 0; 
} 

Ответы [ 2 ]

1 голос
/ 30 марта 2020

Потому что вы не выделяете 2D массив. Вы выделяете набор одномерных массивов, и эти выделения не обязательно должны быть смежными (большинство реализаций malloc резервируют несколько байтов для хранения размера выделенного блока).

Для динамического выделения "true" 2D-массив, в котором количество строк и столбцов не известно до времени выполнения, вы должны сделать что-то вроде этого:

stat (*arr)[c] = malloc( sizeof *arr * r );

, которое будет смежным, как любой "нормальный" 2D-массив.

Но ...

Строго говоря, это поведение не определено - поскольку arr указывает на VLA, выражение sizeof *arr должен оцениваться в время выполнения , а не во время компиляции, и arr не является допустимым значением указателя в этой точке. Я никогда не видел такого сбоя ни в одной из реализаций, которые я использовал, но это не значит, что где-то не получится. Если бы вместо этого c были постоянными, как

stat (*arr)[3] = malloc( sizeof *arr * r );

, то проблем не было бы, и это было бы предпочтительным способом динамического выделения массива Nx3.

Если вам нужно, чтобы все элементы массива были смежными (чтобы вы могли перемещаться по всему массиву с помощью указателя или чего-то в этом роде), тогда самый безопасный вариант - выделить вашу память как одномерный массив:

stat *arr = malloc( sizeof *arr * r * c );

и вычислите смещения вручную:

x = arr[ i * r + j ];

Если вы хотите удобство двумерной нотации, вы можете попробовать создать указатель и параметр, указывающий на начало массива, что-то вроде

stat (*ptr)[c] = (stat (*)[c]) arr;

но такой тип псевдонимов указателей также не определен, если типы указателей несовместимы, и у нас нет оснований ожидать, что указатель на T совместим с указателем на массив T.

1 голос
/ 30 марта 2020

В комментариях к вашему вопросу есть самый важный совет - не беспокойтесь о том, где mallo c помещает вашу память. Нет уверенности, что это будет в любом порядке. Он может определять распределение для достижения различных оптимизаций или предположений и может варьироваться от одного исполнения к другому. Если ничего другого, другие распределения памяти, вызовы free, сборка мусора (на языках с G C, то есть) между вашими вызовами mallo c, повлияет на местоположение следующего выделения.

Это также может варьироваться в зависимости от компилятора, параметров компилятора, ОС и т. Д. c.

Что касается конкретной c причины, по которой ваши выделения имеют разрыв в 16 байт, это невозможно сказать без более глубокое и, вероятно, очень глубокое понимание вашего сценария. Кстати, вы не включили вывод вашего printf в ваш вопрос.

Но если бы мне пришлось угадывать, я бы сказал, что диспетчер памяти выравнивал распределение по границам памяти ... возможно, 32-байтовую или 64-байтовую границу.

Вы выделяете 4 * sizeof(int). Если int равен 4 байта в вашей системе, это 16 байтов. Если вашему malloc нравится выстраивать размер до 32 байтов, это может объяснить 16-байтовые пробелы, которые вы видите.

Но опять же ... это всего лишь предположение. Простой ответ ... вам все равно.

Но если вы по какой-то причине заботитесь о DO , вам, вероятно, нужно сделать свое собственное распределение. malloc гораздо больший кусок памяти, а затем управляйте своими собственными указателями и выделениями внутри.

...