在C语言中函数内分配二维数组的内存

18
如何在函数中为二维数组分配动态内存? 我尝试了以下方法:
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个回答

34
你的代码有误,错误出在*arr[i]=(int*)malloc(m*sizeof(int));这一行,因为[]运算符的precedence优先级高于*解引用运算符:在表达式*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,而不是在循环中调用。因此,这种技术应该更好。

1
如果这个答案解决了你的问题,请点击左侧的“勾选标记”将其接受为正确答案。 - Lundin

4
考虑以下内容:仅单一分配。
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);

3
如果您的数组不需要调整大小(当然,您可以这样做,但会更加复杂),在C语言中构建二维数组有一种更简单/更有效的方法。
请参考http://c-faq.com/aryptr/dynmuldimary.html
第二种方法(对于名为array2的数组)非常简单,较少痛苦(尝试添加malloc返回值的测试),并且效率更高。
我刚刚进行了基准测试,对于一个200x100的数组,分配和释放100000次:
- 方法1:1.8秒 - 方法2:47毫秒
而且数组中的数据将更加连续,这可能会加速运行速度(您可能会获得一些更有效的技术来复制、重置...以此方式分配的数组)。

1
我部分地同意你的观点。如果你正在处理巨大的数组(几百甚至几千兆字节),或者在某些受限制的系统中,这种方法可能不太适合,因为你可能会遇到来自堆的大块内存分配问题(但无论你选择哪种方法,都有一些机会让你感到困扰)。但对于大多数情况来说,这种方法非常安全,而且真正高效。 - Cyrille Faucheux

2

与其将内存分配到多个不同的块中,一个更好的选择是在连续的内存块中进行分配。

按照以下步骤操作:

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

1
那是一种不必要地复杂的为数组分配空间的方式。考虑使用这个惯用法:
int main(void) {
    size_t m = 4, n = 3;
    int (*array)[m];
    array = malloc(n * sizeof *array);
    free(array);
}

2d_array 不是一个有效的标识符! - Antti Haapala -- Слава Україні

0
我已经尝试了以下代码来为二维数组分配内存。
    #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,以及在循环中的下一次迭代中。


-1
尝试以下代码:
 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));
} 

-1

使用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;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接