指针问题梳理

来源:互联网 发布:2017年网络热点话题 编辑:程序博客网 时间:2024/06/16 01:53

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

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

存储结构如下:

/*树的存储结构*/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); //所以成功传入并没有发生错误}

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

原创粉丝点击