динамическое размещение / освобождение 2D и 3D массивов - PullRequest
11 голосов
/ 01 декабря 2009

Я знаю об алгоритмах динамического выделения / освобождения 2D-массива, однако я не слишком уверен в том же для 3D-массивов.
Используя эти знания и немного симметрии, я придумал следующий код.
(Мне было трудно визуализировать в 3D во время кодирования).

Пожалуйста, прокомментируйте правильность и предложите лучшую альтернативу (с точки зрения эффективности или интуитивно), если таковая имеется.
Кроме того, я думаю, что к этим 2D и 3D массивам можно получить доступ, как к статическим массивам, таким как arr2D [2] [3] и
. arr3D [2] [3] [2]. Правильно?

Код для 2D

//allocate a 2D array
int** allocate2D(int rows,int cols)
{
    int **arr2D;
    int i;

    arr2D = (int**)malloc(rows*sizeof(int*));
    for(i=0;i<rows;i++)
    {
        arr2D[i] = (int*)malloc(cols*sizeof(int));
    }
}

//deallocate a 2D array
void deallocate2D(int** arr2D,int rows)
{
    int i;

    for(i=0;i<rows;i++)
    {
        free(arr2D[i]);
    }

    free(arr2D);
}  

Код для 3D

//allocate a 3D array
int*** allocate3D(int l,int m,int n)
{
int ***arr3D;
int i,j,k;

arr3D = (int***)malloc(l * sizeof(int **));

for(i=0;i<l;i++)
{
    arr3D[i] = (int**)malloc(m * sizeof(int*));
    for(j=0;j<m;j++)
    {
        arr3D[i][j] = (int*)malloc(n*sizeof(int));
    }
}

return arr3D;
}

//deallocate a 3D array
void deallocate3D(int arr3D,int l,int m)
{
    int i,j;

    for(i=0;i<l;i++)
    {
        for(int j=0;j<m;j++)
        {
            free(arr3D[i][j]);
        }
        free(arr3D[i]);
    }
    free(arr3D);
}

Ответы [ 4 ]

11 голосов
/ 01 декабря 2009

Вы также можете выделить один массив и вычислить отдельные индексы. Это требует меньше вызовов распределителя и приводит как к меньшей фрагментации, так и к лучшему использованию кэша.

typedef struct {
  int a;
  int b;
  int* data;
} Int2d;

Int2d arr2d = { 2, 3 };
arr2d.data = malloc(arr2d.a * arr2d.b * sizeof *arr2d.data);

Теперь arr2d[r][c] становится arr2d.data[r * arr2d.b + c]. Распределение - один свободный (). В качестве бонуса вы всегда будете иметь при себе размеры динамического массива.

экстраполяция в 3d:

typedef struct {
  int a;
  int b;
  int c;
  int* data;
} Int3d;

Int3d arr3d = { 2, 3, 4 };
arr3d.data = malloc(arr3d.a * arr3d.b * arr3d.c * sizeof *arr3d.data);

//arr3d[r][c][d]
// becomes:
arr3d.data[r * (arr3d.b * arr3d.c) + c * arr3d.c + d];

Вы должны инкапсулировать эти операции с индексами (и (де) выделения в этом отношении) в отдельной функции или макросе.

(Имена для r, c и d могли бы быть лучше & mdash; я собирался указать строку, столбец и глубину. Хотя a, b и c являются пределами их соответствующих измерений, вы можете предпочесть что-то вроде n1, n2, n3 там, или даже использовать массив для них.)

4 голосов
/ 01 декабря 2009

arr3d должен быть тройным указателем, а не просто int. В противном случае выглядит нормально:

void deallocate3D(int*** arr3D,int l,int m)
{
    int i,j;

    for(i=0;i<l;i++)
    {
        for(int j=0;j<m;j++)
        {
                free(arr3D[i][j]);
        }
        free(arr3D[i]);
    }
    free(arr3D);
}

arr3D является указателем на указатель на указатель, поэтому arr3D [i] является указателем на указатель, а arr3D [i] [j] просто указатель. Правильно сначала освободить наименьшее измерение в цикле, а затем подниматься до размеров, пока не освободится сам arr3D.

Также более идиоматично давать malloc размер указанного типа неявно. Вместо:

  arr3D[i] = (int**)malloc(m * sizeof(int*));

Сделай это:

  arr3D[i] = (int**)malloc(m * sizeof(*arr3D[i]));

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

1 голос
/ 29 декабря 2012

Вы можете увидеть ниже код:

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

void main()
{
    //  Array 3 Dimensions
    int x = 4, y = 5, z = 6;

    //  Array Iterators
    int i, j, k;

    //  Allocate 3D Array
    int *allElements = malloc(x * y * z * sizeof(int));
    int ***array3D = malloc(x * sizeof(int **));

    for(i = 0; i < x; i++)
    {
        array3D[i] = malloc(y * sizeof(int *));

        for(j = 0; j < y; j++)
        {
            array3D[i][j] = allElements + (i * y * z) + (j * z);
        }
    }

    //  Access array elements
    for(i = 0; i < x; i++)
    {
        printf("%d\n", i);

        for(j = 0; j < y; j++)
        {
            printf("\n");

            for(k = 0; k < z; k++)
            {
                array3D[i][j][k] = (i * y * z) + (j * z) + k;
                printf("\t%d", array3D[i][j][k]);
            }
        }

        printf("\n\n");
    }

    //  Deallocate 3D array
    free(allElements);
    for(i = 0; i < x; i++)
    {
        free(array3D[i]);
    }
    free (array3D);
}

Подробнее см. По этой ссылке 3d-массив

0 голосов
/ 18 декабря 2013

Это версия идеи в вопросе, но с использованием только одного malloc, вдохновленного другими ответами. Это позволяет интуитивно использовать квадратные скобки и легко чистить. Я надеюсь, что это не делает никаких конкретных предположений о реализации компилятора.

int main(int argc, char *argv[])
{
  int **array, i, j;
  array = allocate2d(3, 4);
  for (i = 0; i < 3; i++)
  {
    for (j = 0; j < 4; j++)
    {
      array[i][j] = j + i + 1;
    }
  }
  for (i = 0; i < 3; i++)
  {
    for (j = 0; j < 4; j++)
    {
      printf("array[%d][%d] = %d\n", i, j, array[i][j]);
    }
  }
  free(array);
  return EXIT_SUCCESS;
}

int **allocate2d(int x, int y)
{
  int i;
  int **array = malloc(sizeof(int *) * x + sizeof(int) * x * y);
  for (i = 0; i < x; i++)
  {
    array[i] = ((int *)(array + x)) + y * i;
  }
  return array;
}
...