zoukankan      html  css  js  c++  java
  • 二级指针

    [cpp] view plaincopy
    1   void remove_if(node ** head, remove_fn rm)    
    2   {    
    3       for (node** curr = head; *curr; )    
    4       {    
    5           node * entry = *curr;    
    6           if (rm(entry))    
    7           {    
    8               *curr = entry->next;     
    9               free(entry);    
    10           }    
    11           else    
    12               curr = &entry->next;     
    13       }    
    14   }   
    上面的例子就是文章给出的一个关于二级指针的例子,文章给出的评论是,最关键的部分在于:链表中的链接都是指针,因此指针到指针是修改链表的首选方案。

         我对作者的用法起初是不大理解,我想不大理解的根源是我对程序对堆栈的用法还不够深入了解。首先,采用一级指针最好是方便修改指针对象的值,采用二级指针最好是方便修改指针的值。理解了这两点,对上面的用法也就可以理解了,函数的用意是删除指定的链表节点,传统的用法是采用一级指针,传入链表头节点,然后判断删除的是头节点,还是其他节点,然后依次寻找一下一个节点。但是linus认为采用这种用法的人不懂指针,懂指针的人采用上面的做法。

        分析一下上面的代码,有两行代码,第8行和第12行,这两行的用法确实高明,第8行改变指针的指向为下一个节点,不论是头节点还是其他节点都适用,第12行改变指针本身的指向为下一个节点,这个好处是不改变调用函数指针的指向。


    如果用create()那必须用NODE **,因为函数要对NODE* 操作,如果参数只传
    NODE*, 那只是对NODE* 做了一份拷贝,当返回时函数里的NODE*被摧毁,你函数体
    外也得不到什么。
    例如:
      void swap(int a, int b)  
     {
         int temp = a;
         a = b;
         b = temp;
      }

      void swap1(int *a, int *b)
      {
        int temp = *a;
        *a = *b;
        *b = temp;
      }

      void main()
     {
       int m = 1, n = 2;
       swap(m, n);
       cout << m << endl;  //1
       cout << n << endl;  //2 没有变化

       swap1(&m, &n);
       cout << m << endl;  //2
       cout << n << endl;  //1 有变化
     }
     当然你不喜欢传二级指针,那就传引用 Create(NODE *&p);


    NODE **hpt 一般用在要改变实参指针所指向的内存时!
    也可用 NODE*& rpt 代替!
    是说我传递一个指针要指向函数中新开辟的内存单元,
    在函数返回时我要保留这个新的地址!
    这是 NODE *hpt 所做不到的!
    所以楼主可能没有看错!!!

    例如:

    #include<iostream>
    typedef int NODE;
    using namespace std;

    void fun(NODE **pht)
    {
    *pht = new NODE(10);
    }

    void main(void)
    {
    NODE value = 5;
    NODE* p = &value;
    cout << *p << endl;
    fun(&p);
    cout << *p << endl; //访问p指向的新内存单元
    delete p;
    }

    //如果用*pht则不能实现!而且在函数fun中还有内存泄露!!!

    #include<iostream>
    typedef int NODE;
    using namespace std;

    void fun(NODE *pht)
    {
    pht = new NODE(10);
    }

    void main(void)
    {
    NODE value = 5;
    NODE* p = &value;
    cout << *p << endl;
    fun(p);
    cout << *p << endl;
    }


    总结:指针也是传值传递,当我们要在被掉函数里面改变调用函数一级指针的值时,就需要以二级指针作为参数。这种情况是经常碰到的,比如在链表(无头结点)操作时是通过链表第一个元素来找到其他所有链表中的元素,如果删除操作时删除的正好是第一个元素,那么这时就要改变链表头指针的指向了。当然还有在二叉树操作时当删除的刚好是树根结点,此时也要改变一级指针的指向。

     

    2、有关指针的数据类型小结(来着《c语言程序设计》谭浩强)



    typedef struct _node
    {
    void *data;
    struct _node *prior;
    struct _node *next; 
    }Node,*PNode;
    用来定义指针结构体类型:如PNode p效果同struct _node* p


    void getmem(char* ptr)
    {
        ptr = (char*)malloc(sizeof(char) * 10 );
    }
    这个函数试图在堆上申请一个长度为10的内存空间并返回给ptr。然而编译器只是把ptr的值复制到一个临时变量_ptr中,然后这个内存空间的首地址赋给_ptr,在调用返回之后,_ptr被清0,而ptr并没有得到这个内存区。
    而:
    void getmem(char** ptr)
    {
        *ptr = (char*)malloc(sizeof(char)*10);
    }

    char* getmem(char* ptr)
    {
        ptr = (char*)malloc(sizeof(char*) * 10);
        return ptr;
    }
    是等价的。

    你要是不想用二级指针,可以用返回指针来得到——我只在Linux和UNIX环境下做过。注意c是传值的,一级指针如果不是在返回值中返回,你申请的内存空间在返回是被销毁,而用二级指针,它将是指向你申请的内存的首地址。另外,一定要记住指针是一个值,是内存的编号。


  • 相关阅读:
    TCP/IP断网仍然显示连通状态禁止“媒体感知”
    ASP.NET页面优化,提高载入速度方法大全
    国家气象局提供
    datatable&list<T>
    windows mobile C# net3.5 如何捕捉Arrow的CheckBox的KeyDown事件?
    hhclass 类 RAPI OpenNETCF.Desktop.Communication.DLL相关下载
    string和stringBuilder区别
    windows mobile全屏设置笔记
    CSS浮动(float,clear)通俗讲解
    js图片延时加载(jquery特效)
  • 原文地址:https://www.cnblogs.com/didi520/p/4165488.html
Copyright © 2011-2022 走看看