个人整理学习用,有错误欢迎指正
出现环境
在leetcode的题目中,当使用C语言求解涉及二级指针的题目,或者需要输出类似于{[1,2,3],[2,3,4],...}
这种不止一个数组的结果是,经常看到形如int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {...}
的函数调用格式。先上结论:int* returnSize
是你所返回的二级指针的大小;int** returnColunmnSizes
是你所返回的二级指针中,其中每一个一级指针的大小。
实际意义
先给一张内存的示意图,这对应了leetCode的15题,给一个数组,返回所有的,三数相加为0的三元组,不允许重复。没看过题的只用了解,threeSum()
是一个函数,它返回了一个由三元组组成的二维数组。需要注意的是,该二维数组是由malloc()
得到的,因此在内存中并不是连续存放的,而是像图示那样离散存放的。
程序运行时变量数据保存在栈区中,而一般情况下,不同的栈区是不能互相访问的。需要注意,C语言中,函数调用时传递的值并不是源值,而是复制一份一模一样的值传进函数中去。
因此,如果你在main()
中创建了变量returnSize
,然后传入了threeSum()
中去,threeSum()
中得到的只是returnSize
一个副本,无论怎么改变都不会影响main()
中的returnSize
。因此,当我们需要在threeSum()
中改变一个值并在main()
中取得的话,最好的方式是传给threeSum
一个地址,这样threeSum
通过拷贝得到了一个地址,但仍能通过解引用操作符*
访问并更改到源数据。
上图中,我们真正需要的仅仅是绿色的源数据,其他的一级指针、二级指针只是为了更好的得到源数据。其中,returnSize
与returnColumnSizes
都是围绕着你的返回值:二级指针ret
。通过threeSum
得到的返回值,本质上只是一个地址,占用了一个内存单元。在main
中只能知道它是一个二级地址,但并不知道这个二级地址包含了多少个一级地址,以及每一个一级地址又包含了多少源数据。因此,需要一些辅助变量告诉main()
上述信息。
returnSize
关于二级地址含含有多少个一级地址,仅仅需要一个值:returnSize
,比如returnSize = 4
,那么ret[0],ret[1],ret[2],ret[3]
这四个值存储的就是有效的一级地址。由于要在threeSum()
中修改这个值,因此不能直接传递returnSize
,而是将某一个内存单元的地址传给threeSum()
函数,并将这个地址,而不是其对应的内存单元起名为returnSize
(不是我故意绕的,是leetCode就这么规定的),因此returnSize
就由单纯的一个值变成了一个一级指针。
returnColumnSizes
有了ret
含有的一级指针的个数,现在还差一件事尚未明了:每一个一级指针又含有多少个数据呢?针对本体来说,由于存放的是三元组,因此每一个一级指针都存放有3个数据。但是并非所有题目都会让你返回三元组。其他题目有可能出现让你返回的数据为{[0],[1,2,3],[1,2]}
这种情况。因此,你需要一个一维数组来记录每一个一级指针所对应的数据的个数。由于这个数据已经是一个一维数组了,要想在不同的函数间传递并修改这些值,必须再将这个一维数组的地址,也就是一个二级地址传入threeSum()
,这个二级地址我们取名为returnColumnSizes
。
使用
一般在leetCode中,都需要你自己去malloc()
这两个变量所占用的空间,并修改其值。
你所返回的二级指针,其中最多可能包含多少个一级指针,就给returnColumnSizes
申请多少个对应 int 的大小的空间。比如最多可能返回1000个三元组,那么最好在一开始就给returnColumnSizes
申请1000个int大小的空间,之后每次给(*returnSize)++
的时候顺便给(*returnColumnSizes)[*returnSize]
赋值就可以了。