问题分析
力扣的题目特点是不需要自己完成输入输出,只需要编写实现算法的函数即可。在刚开始使用C语言在LeetCode刷题碰到的一个问题就是,当题目要求返回一个数组(一维或二维)时,我们写的代码常常发生如下所示的内存错误。
在LeetCode上使用C语言返回一个数组时,根据返回的数组是一维数组还是二维数组,题目分别会有如下说明:
- 当题目要求返回一个一维数组时:
这里要求,返回的数组必须通过动态开辟(malloc,calloc,realloc),并且函数func中都含有一个一级指针参数returnSize,这个参数指向一个值为返回数组大小的整形变量,也就是说,*returnSize就是返回数组中含有元素的个数。/** * Note: The returned array must be malloced, assume caller calls free(). */ int* func(int* returnSize) { // do something }
- 当题目要求返回一个二维数组时:
这里要求,返回的数组必须通过动态开辟(malloc,calloc,realloc),并且函数func中懂包含两个参数,分别是一级指针returnSize和二级指针returnColumnSizes,其中,returnSize指向一个值为返回二维数组行数的整形变量,也就是说,*returnSize就是返回二维数组的行数,而returnColumnSizes指向一个存储了返回二维数组各行长度的一维数组,也就是说,(*returnColumnSizes)[i]就是返回二维数组第i行的元素个数。/** * Return an array of arrays of size *returnSize. * The sizes of the arrays are returned as *returnColumnSizes array. * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free(). */ int** func(int* returnSize, int** returnColumnSizes) { // do something }
解决方案
那么,为什么LeetCode使用C语言返回数组时需要这样设计呢?LeetCode的输出功能不需要我们完成,但是很好想象,如果我们需要输出得到的数组,那么对于一个一维数组,我们需要知道它的大小,对于一个二维数组,我们需要知道它的行数和各行需要输出的元素个数,如下所示:
- 当题目要求返回一个一维数组时:
我们需要知道返回数组的大小,由于C语言函数的返回值至多只能为1个,因此可以将某个需要返回的值通过作为函数的参数进行修改,这里需要知道数组的大小size,因此将size的地址传入,在函数内部进行修改,这样size就是返回数组的大小。(形参的改变不影响实参,如果直接将size作为参数那么在函数内对size的修改不影响主函数内size的值)int* func(int* returnSize) { int* ans = (int*)malloc(sizeof(int) * 10); *returnSize = 10; return ans; } int main() { int size = 0; int* arr = func(&size); for(int i = 0; i < size; i++) printf("%d ", arr[i]); free(arr); return 0; }
-
当题目要求返回一个二维数组时:
int** func(int* returnSize, int** returnColumnSizes) { int** ans = (int**)malloc(sizeof(int*) * 10); for(int i = 0; i < 10; i++) ans[i] = malloc(sizeof(int) * 5); *returnColumnSizes = (int*)malloc(sizeof(int) * 10); for(int i = 0; i < 10; i++) (*returnColumnSizes)[i] = 5; *returnSize = 10; return ans; } int main() { int size = 0; int* ColSizes = NULL; int** ans = func(&size, &ColSizes); for(int i = 0; i < size; i++) { for(int j = 0; j < ColSizes[i]; j++) printf("%d ", ans[i][j]); printf("\n"); } return 0; }
与返回一维数组的情况类似,size代表二维数组的行数,而主函数里的指针ColSizes可以理解为一个一维数组,ColSizes[i]为二维数组第i行的元素个数(或者是需要输出的元素个数),而ColSizes的元素个数为二维数组的行数,但是,主函数里的ColSizes只是一个空指针,需要我们在函数func内对其进行修改,类似地,需要传入的是它的地址,也就是一个二级指针。在函数func内部,首先应该为ColSizes开辟一块空间来存放各行的元素个数。