指针问题梳理

指针好像一直都是一个头疼的问题,从一级指针到二级指针的运用,总是经常出错。今天遇到的一个二级指针的问题,花了很多时间,想了一个比较合理的解释。

今天在数据结构的实验中,用一个二级指针作为参数来写了一个二叉树的建立。大概的函数代码如下:

存储结构如下:


/*树的存储结构*/
typedef struct Tree 
{
    char data;
    struct Tree *Lift;
    struct Tree *Right;
}Tree,*Btree;
/*二级指针建立二叉树*/
void crea(Btree *root)
{
    printf("%p\n",root);
    char ch;
    ch = getchar();
    if(ch=='#')
    {
        (*root) =  NULL;
    }
    else
    {
        *root=(Tree *)malloc(sizeof(Tree));
        (*root)->data = ch;
        // printf("ch=%ckk\n",ch);
        if((*root)==NULL)
        {
            exit(0);
        }
        crea((&(*root)->Right));
        crea((&(*root)->Lift));
    }
}

然后为了测试这个创建二叉树的函数对不对,我在主函数里,简单地定义了一个二级指针,给传了进去,然后问题来了。

int main()
{
    Btree *p;
    crea(p);
}

然后程序,跑到malloc的时候就断错误了。

 *root=(Tree *)malloc(sizeof(Tree));
 printf("%c\n",ch);//该输出是输出不了的,以段错误结束

然后改了下主函数传递参数的方式,就能够正常的malloc了。

int main()
{
    Btree p; //一级指针
    crea(&p); //传入一级指针本身的地址
}

同样相当于二级指针,但是为什么第一种就会出现断错误。主要原因是malloc一块明确的空间后要给一个明确的地址。


最简单的列子(首先搞懂自定义函数形参怎么传递的)

#include<stdio.h>
#include<stdlib.h>

int fun(int a)
{
    a++;
    return a;
}

int main()
{
    int b = 0;
    int a = 10;
    fun(a);
    b = fun(b);
    printf("b=%d\n",b);
    printf("a=%d\n",a);
    return 0;
}

在C语言中,函数的参数传递是值传递,素以fun(a),只是把a的值传递给了自定义函数中的a,然后a在自定义函数中自加,但是主函数里面的a是不变的,只是多了return,return会把a自加的结果赋值给主函数中的b。结果如下:
这里写图片描述

但是这个传递给这个自定义函数的是一个主函数里a变量的地址,那么在自定义函数中就会对这个a进行改变。

#include<stdio.h>
#include<stdlib.h>

int fun(int *a)
{
    (*a)++;
    return *a;
}

int main()
{
    int b = 0;
    int a = 10;
    fun(&a);
    b = fun(&b);
    printf("b=%d\n",b);
    printf("a=%d\n",a);
    return 0;
}

这里写图片描述
第二个代码中,在形参定义的是一个指向int类型的指针,而从主函数中传入的是a变量的地址,那么形参将获得主函数中a的地址,然后直接在a的地址上操作其内容。而第一个代码中,形参只是获得了a的数值,并没有获得其本身的地址,所以没有对主函数中的变量a进行改变的权利。第二个代码中,传递的值是a的地址值,直接从地址值对a进行了改变。

然后理解中的指针(有它自己的地址值,和存储的区域)

地址为100 地址为200
存储的内容 存储的内容

所以我理解的二级指针(**p)大概就是:

100 104 108
存地址104 存地址108 存一个a

所以一级指针便是(*p):

100 104
存地址104 a

最后回到原来的错误代码

int main()
{
    Btree *p;
    crea(p);
}

其中p是一个二级指针,因为Btree是*Btree。此时传入的是二级指针,是一个指针变量,并没有明确地指向某个空间。在自定义函数creat接收它之后,root指向了p,然后malloc开辟了一个明确的空间,接下来root将指向这个随机空间的首地址,但是在此之前,root指向了p,而p又没有指向一个明确的空间,所以此时的malloc会出错。

int main()
{
    Btree p;
    crea(&p);
}

第二个代码中,p是一个一级指针变量,但是传入的时候&p,此时假如p指针本身的地址是100,那么就是将100传给了变量root,root是一个二级指针,是存储指针的指针变量,此时将100存入了root存储内容中,malloc一块空间后,再降root存储的这个地址的指针再指向malloc开辟的空间。此时malloc赋给了一个明确的指针。所以不会出错。

再举一个简单的类比例子

#include<stdio.h>
#include<stdlib.h>

int main()
{
    int *p;
    *p = 9;
    printf("p=%d\n",*p);
}

会出现断错误,因为*p可以存内容为9的地址,但是不能直接降9赋给它,因为此时P没有明确地指向一个空间。可以用malloc给它指向一个明确的空间后,才能降9存入到其中。如下:

#include<stdio.h>
#include<stdlib.h>

int main()
{
    int *p;
    p = (int *)malloc(4);
    *p = 9;
    printf("p=%d\n",*p);
}

或者这样:

#include<stdio.h>
#include<stdlib.h>

int main()
{
    int a = 9;//申请一个地址,初始化为9.
    int *p;
    //p = (int *)malloc(4);
    p = &a;
    printf("p=%d\n",*p);
}

所以今天的代码还可以做这样的改正。

int main()
{
    Btree *p;
    Tree *q=NULL; //申请了一个地址,代号为p,初始化为NULL
    p = &q; //p明确存储了q的地址,因此**p传入之后有了明确指向
    crea(p); //所以成功传入并没有发生错误
}


感觉自己对指针的领悟还有待提升,如果这次这个解释存在错误的话,希望大家可以帮我指出。

猜你喜欢

转载自blog.csdn.net/qq_36573828/article/details/78493681