Leetcode中 ** returnColumnSizes到底是什么?

概 述

刷过题的朋友肯定见过这个 ** returnColumnSizes,或者是* returnSize. 说实话我看到*returnSize的时候是理解的,但是一到了二级指针就止不住的懵逼,在自己研究讨论了两个小时之后,我想明白了。如有疑问请打脸。

其实 ** 的使用,和交换两个整数的 swap 函数是同一个道理。


使用 returnSize 和 returnColumnSizes 的原因

我的理解是,你返回一个数组的时候,只能返回它的指针,但是官方检测的时候到底要检查多少个数据呢?智能检测也太耗资源了,所以需要你告诉它,我前 returnSize 个数据是有用的,后面的数据只是我防止溢出多创建的,让它检查这么多个就好啦。

首先大家要知道这个 returnColumnSizes 在主函数中应该是一个一维数组,每个元素代表了当前排有多少个有效的列,一般这种题会有一个配套的 returnSize 代表共有多少排,这个一维数组,配合着排的总数,就可以让 Leetcode 后台去检查你的答案了。

swap函数

所有指针的入门教学,都会用一个交换函数来告诉你指针的必要性,

如果你对此耳熟能详,请直接跳到下一个分割线。


void swap(int x, int y) {

    int temp;

    temp = x;

    x = y;

    y = temp;

}

int main(void)

{

    int x = 1;

    int y = 0;

    printf("x is %d, y is %d\n", x, y);

    swap(x, y);

    printf("x is %d, y is %d", x, y);   

}
如果我们只是把主函数的 x,y 传进 swap 函数里面,
那么虽然它们在交换函数中被改变了,但是在主函数中并不会改变。
只有你把地址传进去,通过解引用的方式才能够成功改变两个数。
void swap(int *x, int *y) {

    int temp;

    temp = *x;

    *x = *y;

    *y = temp;

}

int main(void)

{

    int x = 1;

    int y = 0;

    printf("x is %d, y is %d\n", x, y);

    swap(&x, &y);

    printf("x is %d, y is %d", x, y);   

}
第一种方法不能改变x,y,是因为在把它们传进函数swap的时候,
其实是复制了他们的值给swap中的参数,而他们本身什么也没做。

第二种方法可以成功交换x,y,是因为系统在保存 x,y的内存地址上面,
直接对他们在内存上储存的值进行了操作。

众生平等,指针也一样

参考swap函数,如果我们把一个指针传进一个函数中,然后想要去改变这个指针上面保存的地址的时候,主函数的指针保存的地址同样不会改变。

下面用一段代码来解释:


void change(int *ptr);

int main(void) 

{

    int *p = NULL;

    change(p);

    printf("%p", p);

}

void change(int *ptr) {

    ptr = 0xff00;          // 给 ptr 赋值一个地址,在函数中,ptr确实会改变,但离开函数块后又会变回去

}

如果你在这里开启调试模式,你会发现,原函数中的ptr的地址,并不会因为进入change()而被改变。

那么实际的leetcode主函数到底是怎么写的呢?我写了一个小例子,在函数中使用了 **

void change(int **ptr);

int main(void) 

{

    int *p = NULL;

    change(&p);

    for (int i = 0; i < 10; i++) {

        printf("%d\n", p[i]);

    }

}

void change(int **ptr) {

    int *res = (int *)malloc(sizeof(int) * 10);

    for (int i = 0; i < 10; i++) {

        res[i] = i;

    }

    *ptr = res;

}
我们可以看一下change的最后一条代码:

*ptr = res;

请问ptr是啥,ptr不就是你传进来的地址?
回主函数找一下,哦~~,原来ptr就是 &p 啊,那翻译过来不就是:

*(&p) = res;          

这不就等于  p = res;  嘛,
相当于我在主函数里建立了一个一级指针,但是我不知道它该指向哪里,
答案里面建立了一个一维数组,我现在告诉主函数里面的一级指针,你指向我这个res就好了。

我不想这么麻烦,行吗? 不行!

我要是不想这么麻烦,不想用 

*(&p) = res;  

可以么? 为什么我不直接把主函数中的一级指针直接传进去,然后在直接把 res 赋值给 ptr 呢?

反正         *(&p) = res;      和     p = res;                  完全等价嘛!!!

代码我都给你改好了:


void change(int *ptr);

int main(void) 

{

    int *p = NULL;

    change(p);

    for (int i = 0; i < 10; i++) {

        printf("%d\n", p[i]);

    }

}

void change(int *ptr) {

    int *res = (int *)malloc(sizeof(int) * 10);

    for (int i = 0; i < 10; i++) {

        res[i] = i;

    }

    ptr = res;

}

我可以保证这个程序不会如你想的一样运行,原因在上个分割线,众生平等,指针也一样 那里解释的很清楚。

指针上面,保存着一个地址。当你把指针传入一个函数中的时候,你可以改变这个地址上面保存着的 值 ,但是你没办法改变 原函数 中,这个指针保存的地址。

可能听起来有点抽象,之后我学一下iviso画个图再来补充下就很容易懂了。

那么我们怎么样才能把,这个指针 上面保存的地址,在其他函数中直接给改了呢?简单啊,你把这个指针的地址传进去不就行了。


如果你把 &p 传入 一个 参数是 ** 的函数,那么你就可以通过

*(&p) = res; 

这条代码改变了啊。同样,你传入的这个 &p 也永远没法 改变原函数中的 &p,但是你改变了原函数中的 p。

如果讲到这里,你还是不懂,那就别看了,自己去动手,把我上面的代码都运行一下,调试一下,你就懂了,光看还是有点难理解的。


指针误区

很多同学可能看完我写的东西产生了质疑,指针不就是用来改变值的么?怎么就不行了呢?

那么我们看一下下面指针改变值的成功例子。


void change(int *p) {

    p[0] = 5;

    p[1] = 6;

    p[2] = 7;

}

int main(void) {

    int *p = (int *)malloc(sizeof(int) * 3);

    for (int i = 0; i < 3; i++) {

        p[i] = i;

        printf("%d ", p[i]);

    }

    change(p);

    printf("\n");

    for (int i = 0; i < 3; i++) {

        printf("%d ", p[i]);

    }

}

这里确实成功改变了,但是我们改变的是,指针p上面保存的地址,在内存中储存的值,而不是改变了指针p上保存的地址。


如果你在change中加一句  p = 0xff000; 那么依然是没办法改版 原函数 中 p的地址的。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。