Выделить память 2d массив в функции C

Как выделить динамическую память для 2d массива в функции? Я попробовал так:

int main()
{
  int m=4,n=3;
  int** arr;
  allocate_mem(&arr,n,m);
}


void allocate_mem(int*** arr,int n, int m)
{
  *arr=(int**)malloc(n*sizeof(int*));
  for(int i=0;i<n;i++)
    *arr[i]=(int*)malloc(m*sizeof(int));
} 

Но это не работает.

8 ответов

Решение

Ваш код неверен в *arr[i]=(int*)malloc(m*sizeof(int)); потому что приоритет [] оператор выше, чем * оператор почтения: в выражении *arr[i], первый arr[i] оценивается тогда * применены. Что вам нужно, это обратное (разыменование arr, а затем применить []).

Используйте круглые скобки, как это: (*arr)[i] переопределить приоритет оператора. Теперь ваш код должен выглядеть так:

void allocate_mem(int*** arr, int n, int m)
{
  *arr = (int**)malloc(n*sizeof(int*));
  for(int i=0; i<n; i++)
    (*arr)[i] = (int*)malloc(m*sizeof(int));
} 

Чтобы понять, что происходит в приведенном выше коде, прочитайте этот ответ.

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

void deallocate_mem(int*** arr, int n){
    for (int i = 0; i < n; i++)
        free((*arr)[i]);
    free(*arr); 
}

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

int* allocate_mem(int*** arr, int n, int m)
{
  *arr = (int**)malloc(n * sizeof(int*));
  int *arr_data = malloc( n * m * sizeof(int));
  for(int i=0; i<n; i++)
     (*arr)[i] = arr_data + i * m ;
  return arr_data; //free point
} 

Чтобы освободить эту память:

void deallocate_mem(int*** arr, int* arr_data){
    free(arr_data);
    free(*arr);
}

Обратите внимание, что во втором методе malloc вызывается только два раза, и поэтому в коде освобождения free вызывается только два раза вместо вызова его в цикле. Так что эта техника должна быть лучше.

Учтите это: просто разовое распределение

int** allocate2D(int m, int n)
{
    int **a = (int **)malloc(m * sizeof(int *) + (m * n * sizeof(int)));

    int *mem = (int *)(a + m);

    for(int i = 0; i < m; i++)
    {
        a[i] = mem + (i * n);
    }

    return a;
}

Чтобы бесплатно:

free(a);

Если размер вашего массива не нужно изменять (ну, вы можете, но il будет немного сложнее), есть более простой / более эффективный способ построения 2D-массивов в C.

Взгляните на http://c-faq.com/aryptr/dynmuldimary.html.

Второй метод (для массива с именем array2) довольно простой, менее болезненный (попробуйте добавить тесты для возвращаемого значения malloc) и более эффективный.

Я только что протестировал его для массива 200x100, выделенного и освобожденного 100000 раз:

  • Метод 1: 1,8 с
  • Метод 2: 47 мс

И данные в массиве будут более смежными, что может ускорить процесс (вы можете получить более эффективные методы для копирования, сброса... массива, выделенного таким образом).

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

int** my2DAllocation(int rows,int columns)
{
   int i;
   int header= rows *sizeof(int *);
   int data=rows*cols*sizeof(int);
   int ** rowptr=(int **)malloc(header+data);
   if(rowptr==NULL)
   {
      return NULL:
   }
   int * buf=(int*)(rowptr+rows);
   for(i=0;i<rows;i++)
   {
      rowptr[i]=buf+i*cols;
   } 
   return rowptr;
}

Это излишне сложный способ выделения пространства для массива. Учти это:

int main(void) {
    size_t m = 4, n = 3;
    int (*2D_array)[m];
    2D_array = malloc(n * sizeof *2D_array);
    free(2D_array);
    return 0;
}

Я попытался следующий код для выделения памяти для 2-мерного массива.

    #include<stdio.h>
    #include<malloc.h>
    void main(void)
    {
    int **p;//double pointer holding a 2d array
    int i,j;
    for(i=0;i<3;i++)
    {
    p=(int**)(malloc(sizeof(int*)));//memory allocation for double pointer
    for(j=(3*i+1);j<(3*i+4);j++)
    {
    *p = (int*)(malloc(sizeof(int)));//memory allocation for pointer holding integer array
    **p = j;                  
    printf(" %d",**p);//print integers in a row 
    printf("\n");
    p++;
    }
    }
    }

Вывод вышеуказанного кода:

1 2 3

4 5 6

7 8 9

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

                1    2    3
    1000 -->   100  104  108

                4    5    6
    1004 -->   200  204  208

                7    8    9
    1008 -->   300  304  308 

Исходя из вышесказанного, мы понимаем, что когда мы выделяем память для указателя p, который является двойным указателем, он указывает на массив целых чисел, поэтому в этом примере мы видим, что 0x1000 - это указатель p.

Этот указатель указывает на целочисленный указатель *p, который является массивом целых чисел, когда память выделяется внутри внутреннего цикла for, во время первой итерации указатель равен 0x100, что указывает на целочисленное значение 1, когда мы присваиваем **p = j. Точно так же он будет указывать на 2 и 3 на следующих итерациях в цикле.

Перед следующей итерацией внешнего цикла двойной указатель увеличивается в пределах следующей итерации, как видно в этом примере, указатель теперь имеет значение 0x1004 и указывает на целочисленный указатель, который представляет собой массив целых чисел 4,5,6 и аналогично для следующих итераций в цикле.

Попробуйте следующий код:

 void allocate_mem(int*** arr,int n, int m)
{
  *arr=(int**)malloc(n*sizeof(int*));
  for(int i=0;i<n;i++)
    *(arr+i)=(int*)malloc(m*sizeof(int));
} 

2d массив динамически массив с использованием malloc:

int row = 4;
int column = 4;
int val = 2;
// memory allocation using malloc   

int **arrM = (int**)malloc (row*sizeof(int*));

for (int i=0;i<row;i++)
{
    arrM[i] = (int*)malloc(column*sizeof(int));
    // insert the value for each field
    for (int j =0;j<column;j++,val++)
    {
      arrM[i][j]     = val;
    }
}

// De-allocation

for (int i=0;i<row;i++)
{
    free(arrM[i]);
}
free(arrM);
arrM = 0;

//
// Now using New operator:
//

int **arr = new int*[row];
int k = 1;
for (int i=0;i<row;i++)
{
    arr[i] = new int[column];
    // insert the value for each field
    for (int j =0;j<column;j++,k++)
    {
      arr[i][j]  = k;
    }
}
cout<<"array value is = "<<*(*(arr+0)+0)<<endl;
cout<<"array value is = "<<*(*(arr+3)+2)<<endl;

// Need to deallcate memory;

for (int i=0;i<row;i++)
{
delete [] arr[i];
}
delete []arr;
arr = 0;
Другие вопросы по тегам