关于指针的小发现

126 阅读5分钟

1.以前迷惑

在学习JavaScript时,一直很难理解什么是"引用类型是按照地址传递"中的地址,以及为什么拷贝了引用类型的变量会和该引用类型产生“一改俱改”的“双向绑定”,所以只能死记硬背了。为了理解清楚指针、按地址传递,所以看了下C是怎么回事,也发现了一些有趣的事情。

2.知识回顾。

在C语言中,像int 这类的变量本身是有自己的值和地址的。我们可以打印int 类型的值,也可以通过&符号+变量名从而得到该变量在编译后的地址。

#include <stdio.h>

int main(){
    int a =10;

    printf("the value of a is: %d\n",a);
    printf("the address of a is: %p\n",&a);
}

上面的代码在我的机器的结果如下。

the value of a is: 10
the address of a is: 0x7ffeebce58ac

在C中,变量的地址是以十六进制数进行存储的. 而给a赋新值,其地址在当次编译时是不变的。

    a = 20;

    printf("the value of a is: %d\n",a);
    printf("the address of a is: %p\n",&a);
the value of a is: 20
the address of a is: 0x7ffeebce58ac

而在C中,指针是一种指向变量地址的变量。如上面的0x7ffeebce58ac就是一个地址。定义一个指针方法如下:

    int *pa; //声明指针pa
    pa = &a; //把整型变量a的地址赋给pa

变量pa在没有号的情况下,可以理解为整型变量a的地址,给pa前面加上号,可以理解为去取地址0x7ffeebce58ac的值:

	printf("the address of pa is: %p\n",&pa);
        printf("the value of *pa is: %d\n", *pa);

其结果为

the address of pa is: 0x7ffeebee78a0
the value of *pa is: 20

*pa可以理解成去地址0x7ffeebee78a0取值,而刚刚pa= &a,所以0x7ffeebee78a0里存放着变量a的地址,即10

3.一些发现

老实说,不是很理解为什么“函数的参数应当是二级指针”,所以写了个简单的小实验。

#include <stdio.h>
int main(){
    int a =100;
    int *p1 = &a;
    int **p2 = &p1;
    int ***p3 = &p2;
    int ****p4 = &p3;
    int b =200;
    int c =300;
    int d = 400;
    int e = 500;
    
    printf("the address of p at T0 is %p\n",p1);
    printf("the address of p2 at T0 is %p\n",p2);
    printf("the address of p3 at T0 is %p\n",p3);
    printf("the address of p4 at T0 is %p\n",p4);
    printf("%d,%d,%d,%d\n",a,*p1,**p2,***p3);
    p1=&b;

    printf("the address of b at T1 is :%p\n",&b);
    printf("the address of p at T1 is %p\n",p1);
    printf("the address of p2 at T1 is %p\n",p2);
    printf("the address of p3 at T1 is %p\n",p3);
    printf("the address of p4 at T1 is %p\n",p4);
    printf("%d,%d,%d,%d\n",b,*p1,**p2,***p3);

    *p2 = &c;
    printf("%d,%d,%d,%d\n",c,*p1,**p2,***p3);

    **p3 = &d;
    printf("%d,%d,%d,%d\n",d,*p1,**p2,***p3);

    printf("the address of b at T2 is :%p\n",&d);
    printf("the address of p at T2 is %p\n",p1);
    printf("the address of p2 at T2 is %p\n",p2);
    printf("the address of p3 at T2 is %p\n",p3);
    printf("the address of p4 at T2 is %p\n",p4);

    ***p4 = &e;

    printf("the address of b at T3 is :%p\n",&e);
    printf("the address of p at T3 is %p\n",p1);
    printf("the address of p2 at T3 is %p\n",p2);
    printf("the address of p3 at T3 is %p\n",p3);
    printf("the address of p4 at T3 is %p\n",p4);

    return 0;
}

输出结果为:

the address of p at T0 is 0x7ffee9d8b8a8
the address of p2 at T0 is 0x7ffee9d8b8a0
the address of p3 at T0 is 0x7ffee9d8b898
the address of p4 at T0 is 0x7ffee9d8b890
100,100,100,100
the address of b at T1 is :0x7ffee9d8b884
the address of p at T1 is 0x7ffee9d8b884
the address of p2 at T1 is 0x7ffee9d8b8a0
the address of p3 at T1 is 0x7ffee9d8b898
the address of p4 at T1 is 0x7ffee9d8b890
200,200,200,200
300,300,300,300
400,400,400,400
the address of b at T2 is :0x7ffee9d8b87c
the address of p at T2 is 0x7ffee9d8b87c
the address of p2 at T2 is 0x7ffee9d8b8a0
the address of p3 at T2 is 0x7ffee9d8b898
the address of p4 at T2 is 0x7ffee9d8b890
the address of b at T3 is :0x7ffee9d8b878
the address of p at T3 is 0x7ffee9d8b878
the address of p2 at T3 is 0x7ffee9d8b8a0
the address of p3 at T3 is 0x7ffee9d8b898
the address of p4 at T3 is 0x7ffee9d8b890

在这个实验中,我构建了一个四级指针。愿意是想看看一直指针改变后,二级指针的地址是否会发生变化。然后结论是二级的地址不会变。 然后把指针增加到三级、四级和五级,尝试改变三级指针或四级指针的地址,在观察一二级指针是否会因为高级指针的改变而改变。而结合打印出来的新来看,结论是,当改变一个多级指针(n>=3)中一个指针的指向时,只有一级指针的地址会变(指向原先指针要指向的变量的地址),其他更高级的指针的地址是不变的。

也就是说, 当执行***p4 = &e时,发生了 p4指针拿p3指针的地址,p3指针拿p2指针的地址,p2指针拿p1指针的地址,p1指针再拿变量e的地址(**p3=&dp2=&c类似)。

所以,对于多重指针来说,一级又一级的指针关系,有点像一个回溯至顶点的单向链表。而在JavaScript中,拷贝了引用类型的变量们,就是通过类似链表的机制获得了引用类型的地址,进而实现了数据的双向绑定,从而实现“一改俱改”吧

好开心,又多了一个用不上的知识~~。