看到很多有写malloc的,但是并不是很懂,请问如何用malloc来申请一个二维数组的内存
指针变量也是一种变量,也会占用存储空间,也可以使用&
获取它的地址。
如果一个指针指向另外一个指针,我们就称它为二级指针,或者指向指针的指针。用C语言描述如下:
int x = 1;
int *p1 = &x;
int **p2 = &p1;
当然,还有三级指针,四级指针,几乎很少用到,这里不再累述。大概是这幅样子:
int ***p3 = &p2;
int ****p4 = &p3;
在学习一级指针的时候,我们用过*
进行解引用。一级指针经过一次解引用,变成普通变量。二级指针经过一次解引用,变成一级指针。
int *p1 = *p2;
在 LeetCode 中,选择 C语言 进行求解时,往往出现如下的情况,这是什么意思呢?
int** func(int** matrix, int matrixSize, int* matrixColSize, int* returnSize, int** returnColumnSizes){
}
参数名 | 变量类型 | 实际含义 |
---|---|---|
matrix | 二级指针 | 传入的矩阵首地址 |
matrixSize | 普通变量 | 传入的矩阵的行数 |
matrixColSize | 一级指针 | 传入矩阵每行的列数(注意是每行,所以是数组) |
returnSize | 一级指针 | 传出矩阵的行数,由于需要作为参数返回,所以用指针取地址 |
returnColumnSizes | 二级指针 | 传出矩阵的每行的列数,由于需要作为数组参数返回,所以用二级指针 |
对于returnColumnSizes
这个参数,补充几点:
1)它是一个 指向数组 的 指针,这里数组是行数组;
2)*returnColumnSizes
是实际的那个数组,并且数组的每个元素是 (*returnColumnSizes)[i]
代表的是列数;
3)return
是个前缀,代表它的定位是 返回值,而不是 函数传参;
所谓模板,就是写完以后,每个题目都能套着用,今天我们就来提炼一个有关于二维数组的内存申请的模板。大致声明如下:
int **myMalloc(int r, int c, int* returnSize, int** returnColumnSizes);
其中,返回值代表申请的二维数组(为了方便理解,我们叫矩阵吧)的首地址。r
和c
代表矩阵的行和列,returnSize
是需要返回给调用方的,实际的矩阵的行,我们会在函数内部将它赋值为r
,而returnColumnSizes
也是需要返回给调用方的,只不过需要返回的是一个数组。所以需要用二级指针(思考:为什么返回数组要用二级指针)。
这个函数就可以作为我们的模板函数的,我们接下来来实现一下它:
int **myMalloc(int r, int c, int* returnSize, int** returnColumnSizes) {
int i;
int **ret = (int **)malloc( sizeof(int *) * r ); // (1)
*returnColumnSizes = (int *)malloc( sizeof(int) * r ); // (2)
*returnSize = r; // (3)
for(i = 0; i < r; ++i) {
ret[i] = (int *)malloc( sizeof(int) * c ); // (4)
(*returnColumnSizes)[i] = c; // (5)
}
return ret;
}
r
,首地址为ret
,二维数组的类型为int **
,二维数组中每个元素的类型为一级指针,即int *
,对应sizeof(int *)
这个表达式;r
,由于需要作为参数返回给调用方,所以这里调用了一次解引用;*returnSize
是需要返回的矩阵的行数,调用者不知道这个功能返回的矩阵有多少行,需要实现者告诉他,同样调用一次解引用;c
,即列数;(*returnColumnSizes)
进行赋值;