• C和指针 第13章 高级指针话题 13.1 进一步探讨指向指针的指针


    高级指针话题
        本章介绍了各种各样的涉及指针的技巧。有些技巧非常实用,另外一些技巧则学术味更浓一些,还有一些纯属找乐。但是,这些技巧很好地说明了这门语言的各种原则。
    13.1 进一步探讨指向指针的指针
        上一张使用了指向指针的指针,用于简化向单链表插入新值的函数。另外还存在很多领域,指向指针的指针可以在其中发挥重要的作用。
        这里有一个通用的例子:
        int i;
        int *pi;
        int **ppi;
        如果它们是自动变量,则无法猜测它们的初始值。
        请问下面各条语句的效果是什么呢?
        1. printf( "%d\n", ppi );
        2. printf( "%d\n", &ppi );
        3. *ppi = 5;
        1如果ppi是个自动变量,它就未被初始化,这条语句将打印一个随机值。如果它是个静态变量,这条语句将打印0。
        2这条语句将存储ppi的地址作为十进制整数打印出来。这个值并不是很有用。
        3这条语句的结果是不可预测的。对ppi不应该指向间接访问操作,因为它尚未初始化。接下来的两条语句用处比较大。
        ppi = π
    这条语句把ppi初始化为指向变量pi。以后就可以对ppi执行间接访问操作了。
        *ppi = &i;
    这条语句把pi(通过间接访问)初始化为指向变量i。指向完上面最后两条语句之后,这些变量变成了下面这个样子:
        现在,下面各条语句具有相同的效果:
        i = 'a';
        *pi = 'a';
        **ppi = 'a';
        在一条简单的对i赋值的语句就可以完成任务的情况下,为什么还要使用更为复杂的涉及间接访问的方法呢?这是因为简单赋值并不总是可行,例如链表的插入。在那些函数中,无法使用简单赋值,因为变量名在函数的作用域内部是未知的。函数所拥有的的只是一个指向需要修改的内存位置的指针,所以要对该指针进行间接访问操作以访问需要修改的变量。
        在前一个例子中,变量i是一个整数,pi是一个指向整数的指针。但ppi是一个指向pi的指针,所以它是一个指向整型的指针的指针。假定我们需要另一个变量,它需要指向ppi。那么,它的类型当然是“指向整型的指针的指针的指针”,而且它应该像下面这样声明:
        int ***pppi;
        间接访问的层次越多,需要用到它的次数就越少。但是,一旦真正理解了间接访问,无论出现多少层间接访问,应该都能十分轻松地应付。
        提示:
        只有当确实需要时,才应该使用多层间接访问。不然的话,程序将会变得更庞大、更缓慢并且更难于维护。

    /*
    ** 指向指针的指针。 
    */
    #include <stdio.h>
    #include <stdlib.h>
    int g_i;
    int *g_pi;
    int **g_ppi;
     
    int main( void ){
        int i;
        /* pi is a pointer points to an int */
        int *pi;
        /* ppi is a pointer points to a pointer */
        int **ppi;
        
        /* 
        ** the result of operation is unpredictable.
        ** Because the ppi doesn't be initialized.
        ** *ppi = 5;
        */
        printf( "g_i = %d, i = %d\n", g_i, i );
        printf( "g_pi = %p, g_pi = %d, pi = %p, pi = %d\n", g_pi, g_pi, pi, pi );
        printf( "g_ppi = %p, g_ppi = %d, ppi = %p, ppi = %d\n", g_ppi, g_ppi, ppi, ppi );
        /* ppi is a pointer points to pi */
        ppi = &pi;
        printf( "after ppi = &pi, ppi = %p, &pi = %p, *ppi = %p, pi = %p\n", ppi, &pi, *ppi, pi );
        /* *ppi is a pointer points to i */
        *ppi = &i;
        i = 'a';
        printf( "after *ppi = &i and i = 'a', *ppi = %p, pi = %p, &i = %p\n**ppi = %c, *pi = %c, i = %c\n",
        *ppi, pi, &i, **ppi, *pi, i ); 
        int ***pppi = &ppi;
        printf( "after pppi = &ppi, pppi = %p, &ppi = %p, *pppi = %p, ppi = %p\n", pppi, &ppi, *pppi, ppi );
         
        return EXIT_SUCCESS;
    }
    /* 输出:

    */ 

  • 相关阅读:
    频域分析实践介绍
    Redis缓存何以一枝独秀?以及热门面试题中Redis的核心特性
    面试现场!月薪3w+的这些数据挖掘SQL面试题你都掌握了吗? ⛵
    小程序怎么开发?怎么开发自己的小程序
    c++多态
    JAVA面试题|AQS详细剖析
    了解消息中间件的基础知识
    单商户商城系统功能拆解38—分销应用—分销订单
    Evil.js(罪恶的) —— 代码
    MySQL中记录(Documents)的基本操作——添加记录和查找记录
  • 原文地址:https://blog.csdn.net/weixin_40186813/article/details/125550327