我一直在阅读很多关于分配内存的帖子,我认为我理解这个概念,但我被告知我必须使用类似这样的方法:
double ** malloc_array2d(size_t m, size_t n)
{
double **A;
size_t i;
A = malloc(m * sizeof(double *));
if (A == NULL)
return NULL;
A[0] = (double *) malloc(m * n * sizeof(double));
if (A[0] == NULL)
{
free(A);
return NULL;
}
for (i = 1 ; i < m ; i++)
A[i] = A[0] + i *n;
return A;
}
然后当然我将不得不在以后释放记忆 - 但我不太了解这种方法,更具体地说,我不能真正看到剩下的最后一行会发生什么指针被设置到内存块中(我被告知。而且我不确定在分配完成后如何在矩阵/数组中插入元素。
答案 0 :(得分:2)
使用这种形式的分配,首先要为其他数组分配一个指针数组,如下所示:
T **a = malloc( sizeof *a * N ); // N is the number of rows
sizeof *a
相当于sizeof (T *)
;数组的每个元素都将成为T
的指针。当我们完成后,我们在内存中会有以下内容:
+---+
a: | | a[0]
+---+
| | a[1]
+---+
| | a[2]
+---+
...
+---+
| | a[N-1]
+---+
现在,对于每个元素,我们分配另一个内存块来保存T
类型的每个元素:
a[i] = malloc( sizeof *a[i] * M ); // M is the number of columns
每个a[i]
都有T *
类型,因此sizeof *a[i]
相当于sizeof (T)
。
在完成之后,我们在内存中看起来像这样:
+---+ +---------+---------+ +-----------+
a: | | a[0] ---> | a[0][0] | a[0][1] |...| a[0][M-1] |
+---+ +---------+---------+ +-----------+
| | a[1] ---> | a[1][0] | a[1][1] |...| a[1][M-1] |
+---+ +---------+---------+ +-----------+
| | a[2] ---> | a[2][0] | a[2][1] |...| a[2][M-1] |
+---+ +---------+---------+ +-----------+
...
+---+ +-----------+-----------+ +-------------+
| | a[N-1]--> | a[N-1][0] | a[N-1][1] |...| a[N-1][M-1] |
+---+ +-----------+-----------+ +-------------+
所以基本上你在这里完成的是分配N
单独的M
- T
的元素数组,然后你收集N
中那些数组的指针 - T *
的元素数组。
您可以像a[i][j]
一样访问每个元素,就像任何普通的2D数组一样;请记住表达式a[i]
定义为*(a + i)
;我们从i
中的地址偏移a
个元素(不是字节!),然后取消引用结果。因此a[i][j]
被评估为*(*(a + i) + j )
。
因此,使用这种形式的分配要记住几件事:
数组的“行”在内存中不会连续; a[i][M-1]
之后的内存中的对象(很可能)不会是a[i+1][0]
。
由于每个“行”a[i]
都分配了对malloc
的调用,因此必须在{/ 1}} 之前显式取消分配free
em>您按照a
的相反顺序解除free
{始终malloc
。
即使我们可以将a
视为2D数组,但它没有数组类型,因此您无法使用sizeof a
技巧确定数组的大小;你只能获得指针类型的大小,而不是数组的总大小。因此,您需要自己跟踪数组大小。
答案 1 :(得分:1)
double ** malloc_array2d(size_t m, size_t n){
double **A;
size_t i;
A = malloc(m*sizeof(double *));
if (A == NULL) return NULL;
A[0]=(double *)malloc(m*n*sizeof(double));
if ( A[0] == NULL) {free(A); return NULL;}
for(i=1; i<m; i++) A[i]=A[0]+i*n;
return A;
}
让我们一行一行:
A = malloc(m*sizeof(double *));
此行为m个双指针分配空间。
A[0] = (double *) malloc(m*n*sizeof(double));
A [0]现在是m * n双精度的内存块,这是2d阵列所需的所有双精度。
for (int i = 1; i < m; i++) {A[i] = A[0] + i * n;}
因为每个A [i]是n个双打的块,我们希望A [i]开始i * n从A [0]开始加倍。
因为所有这些都在一个坚实的内存块中,我们可以做一些有趣的事情。例如,A [0] [n]与A [1] [0]完全相同。
此外,因为所有内容都在一个大的内存块中,所以要访问A [i] [j]以获得任何i&lt; m,j&lt; n,我们只需访问A[0] + i*j + j
处的双精度数。这比去A [i]要快得多,它指向一个双* B,并找到B [j]。
内存管理是一个难以理解的主题,需要一些时间。希望这更有意义,我希望我不会让你更加困惑:)
答案 2 :(得分:-2)
你必须使poitners指针的每个指针指向有效的malloc()
ed数据。
for (int i = 0 ; i < n ; ++i)
A[i] = (double *) malloc(m * sizeof(double));
您也可以一次性分配所有内容,但后续符号A[i][j]
将无效。