高级程序员的必经之路-指针(中级篇,二级指针详解)

迟来的更新,一年前催促我更新的同学们还会看到这一篇文章吗?往事如风,就让我在2023年最后的时刻弥补一下各位的遗憾,今天抽出我一部分时间为你们讲解指针篇的中级部分吧

首先在入门篇的基础上,相信大家已经对指针有了初步的了解和使用能力,那么接下来我将讲解二级指针(多级指针)的理解和应用场景,首先我们来认识一下二级指针,其实很形象,一级指针既然是一个*号,那么二级指针不就是两个*号了吗?没错,二级指针的定义就是两个解引符号加上一个变量名称,至于数据类型不能说和一级指针一模一样,只能说完全相同,我们来看定义二级指针的代码:

int main()

{

        int  **p_2 = NULL;   //定义一个名叫p_2的二级空指针

        int *p_1 = NULL;     //定义一个名叫p_1的一级空指针

        return 0;

}

为了防止大家没在我的初级篇理解透彻,这里给大家说明一下空指针的意思,空指针顾名思义就是没用保存任何地址的指针,不存放任何地址(NULL),和野指针有着一定的区别,野指针存放随机的地址相当危险,作为专业的开发人员初始化指针时一定要置空

二级指针作用其实概括起来并不难,一句话就是用来储存一级指针的地址,解引方式和一级指针相同,但是需要注意的是一层解引是得到一级指针储存的内存,二级解引才是访问一级指针所指向内存的数据,有点绕对吗?看下方代码

int main()

{

        int *p_1 = NULL;

        int  data = 1;

        p_1 = &data;                  //一级指针储存data的地址

        int **p_2 = NULL;   

        p_2 = &p_1;                   //二级指针储存p_1的地址

        std::cout<<*p_1<<std::endl;   //访问data数据

        std::cout<<**p_2<<std::endl;  //访问data数据

        std::cout<<p_1<<std::endl;           //访问data地址              

        std::cout<<*p_2<<std::endl;         //访问data地址

        

        std::cout<<&p_1<<endl;               //访问p_1的地址

        std::cout<<p_2<<std::endl;           //访问p_1的地址

        //所以p_2  = &p_1就是保存了p_1的地址,懂否?

        return 0;

}

那么储存一级指针的地址有什么用呢?我们上次说明了一级指针可以解决形参和实参不一致的问题,那么二级指针是不是同样可以这么使用呢?当然可以了,我们举个例子,这个例子使用了堆空间(这个东西放到高级篇讲解)

void initBlock(int **p)

{

        *p = new int;

}

int main()

{

        int *p=NULL;

        initBlock(&p);

        *p = 0;

        cout<<*p<<endl;

        return 0;

}

好了,相信有的同学看到这里看到有点疑惑,如果有以下疑惑:为什么形参采用二级指针? 

那么你们可以动手把我的形参改成一级的,然后传入参数去掉&符号,运行一下就知道结果了。

其实以上方式是我们自定义数据结构初始化的时候经常使用的操作,比如链式结构等等....

二级指针的第二种用法,将函数内部的变量带出来,看过我博客的都知道栈帧这个东西,函数结束调用时会自动释放掉栈,那么变量自然也就不存在了,但是我们可以使用二级指针保存内存条上面的地址进行操作(不建议),栈上的空间被释放内存会变得十分不稳定。所以我们使用static变量,函数结束调用时内存依然存在,不会消失,那么怎么玩呢?看以下代码:

void test(int **p_2)

{

        static int k = 1;

        *p_2 = &k;

}

int main()

{

        int **p_2 = NULL;

        int *p_1 = NULL;

        p_2 = &p_1;

        test(p_2);

        cout<<**p_2<<endl;

        return 0;

}

怎么样?神奇吗?其实这个方式几乎用不到,但是我想告诉你们的是,任何方式只要懂得了他的原理,那么就不会因为问题改变而手足无措,接下来我们看看原理图:

最终结果如上图所示。

其实我们只要知道一个道理即可,任何指针,哪怕十级指针也是变量,那么变量就要遵守变量的规则,堆,栈等等,学习从来不是散乱无章的,而是系统的,希望大家可以有个系统的学习。

最后,请大家思考,既然二级指针保存的是一级指针的地址,那么一级指针又是变量,那么他的地址也是整数,所以二级指针和一级指针所保存的类型相同?

答案是对的,在C语言语法中指针可以直接被赋值为整形,但是C++去除了这个操作,为了更加安全所以做了保护措施,大家可以把.cpp文件改成.c然后去尝试这个操作,相信会有更多的理解

最后,马上元旦了,祝大家元旦节愉快

  • 21
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值