zoukankan      html  css  js  c++  java
  • C 真正理解二级指针

    指针是C语言的灵魂,我想对于一级指针大家应该都很熟悉,也经常用到:比如说对于字符串的处理,函数参数的“值,结果传递”等,对于二级指针或者多级指针,我想理解起来也是比较容易的,比如二级指针就是指向指针的指针.....n级指针就是....

     

                                          p    *p   **p
                                          ---  ---  ----
                                          | |->| |->|  |
                                          ---  ---  |  |
                                                    |  |
                                                    ----

      

    但是可能大家比较不容易理解的是,二级指针或者多级指针用在哪里呢?怎么使用呢?有没有必要用呢?

    现在我就谈谈C指针的比较经常用到的地方:

    我们都知道C语言中函数传递参数都是传递"值"的,如下:

    void fun(void)
    {
         int tmp = 0;
         change(tmp);
         printf("################ tmp = %d /n");
         return ;
    }
    
    void change(int tmp_t)
    {
       tmp_t =1;
       return;
    } 

    这个时候fun()中打印出来的tmp值还是0,因为我们传递的是“值”,如果你想在函数change()中修改这个tmp的值能在fun()中生效的话,那么就需要用指针来传递了如下:

    void fun(void)
    {
         int tmp = 0;
    
         change(&tmp);
    
         printf("################ tmp = %d /n");
    
         return ;
    }
    
     
    
    void change(int *tmp_t)
    {
       *tmp_t =1;
    
       return;
    }

    这个时候fun()中打印出来的tmp值就是1了,因为我们此时传进来的是tmp的地址,所以我们在change()中tmp_t就是tmp的地址了,而对于*tmp_t的操作其实就是对tmp的操作了。

    到这里的时候我们可以试想一下,我们通过传递指针来达到修改一个值的目的,那么当你需要修改一个指针的时候呢,这个时候我们就需要指针的指针了,如下:

    int fun(void)
    {
         int *buf ;
    
         int ret ;
    
         ret = mem_init(&buf);
    
         return ret;
    }
    
    int mem_init(int **buf_t)
    {
      *buf_t = malloc(100);
    
      return 1;
    }  

    通过上面我们可以发现,fun()函数通过调用men_init()函数来实现给buf分配内存空间的目的。首先buf是我们定义的一个指针,&buf则是指向buf的指针(二级指针),我们通过把&buf传递个men_init()函数,那么此时二级指针buf_t=&buf了,所以说buf_t是指向buf的指针,那么对于*buf_t的操作其实就是对buf的操作了,这样fun()就可以通过men_init()来分配内存了。

    补充一点:对于定义的int **buf_t中,二级指针buf_t=&buf,指向为buf(还是一个指针),一级指针*buf_t=buf,指向为*buf,值**buf_t= *buf。

    对于n级指针的使用也是差不多这样了,这是本人的一点理解,如果有不对,希望大家多多指导。

    易混淆的点


    虽然修改一个指针指向的地址需要二级指针,但是这不等于我们修改一个指针指向的目标的值时也需要二级指针,因为 C 语言中有解引用符的存在。比如当我们只需要修改一个指针中的 val 或 next 字段时,可以直接使用 node->val = new_val 。

    运用实例


      例一:声明一个结构体类型

    typedef struct node
    {
    
    }TreeNode,*Tree;
    

     

      在main函数中我们定义一个Tree型的变量t,记Tree=t;

      现在声明一个Create函数,目的是创建一棵树,显然,这需要传入地址进行操作,那么参数应该设定为什么呢?

      由这篇文章我们知道,当我们通过传递指针来修改值,当我们需要修改的是指针时,那么就需要通过传递指针的指针进行修改了,

    正确代码如下:     

    Void Create(Tree *t);
    
    int main()
    {
        Tree t;
        Create(&t);
        return 0;        
    }

       

      例二:判断int main()的形参列表(int argc,char **argv)

      相关代码:

    //假设传递给程序的选项为 prog -d -o ofile data0
    
    int main(int argc,char **argv)
    {
        for(int x=0 ; x<=5 ; x++)
             cout << argv[x] << " ";  //输出:程序名字 prog -d -o ofile data0
    return 0; } 

      我们知道,数组名等于一级指针,那么传入的是名为argv的二级指针,可以认为传入的是指向char*类型的指针数组,内容存储的是指向字符串(char *)的指针,所以argv[x]表示的是在从argv位置起第X+1个字符串(argv[0]为第一个字符串)。

      通过这个原理,将代码改成如下形式也是可以的:

    //假设传递给程序的选项为 prog -d -o ofile data0
    
    int main(int argc,char **argv)
    {
        for(int x=0 ; x<=5 ; x++)
             cout << *argv++ << " "; //输出:程序名字 prog -d -o ofile data0
        return 0;
    }
    

     参考资料


    《真正理解二级指针》:https://blog.csdn.net/liaoxinmeng/article/details/5811097

    《二级指针作用详解》:https://zhuanlan.zhihu.com/p/89481530

    ————全心全意投入,拒绝画地为牢
  • 相关阅读:
    DICOM:DICOM3.0网络通信协议
    Maven使用—拷贝Maven依赖jar包到指定目录
    Spring Boot使用JavaMailSender发送邮件
    SpringBoot配置Email发送功能
    MariaDB 安装与启动 过程记录
    ESXi与Linux主机配置syslog日志上传远程服务器
    Linux--忘记MySQL密码的解决方法和输入mysqld_safe --skip-grant-tables &后无法进入MySQL的解决方法
    centos killall安装
    centos安装lspci工具
    oracle创建job和删除job
  • 原文地址:https://www.cnblogs.com/Bw98blogs/p/7202766.html
Copyright © 2011-2022 走看看