指针的指针
2016-07-24 11:46
316 查看
从交换两个数谈起。一般地,如果我们要交换两个数,不论是是使用指针,还是直接使用对应的类型。要么引入一个临时变量,要么进行异或操作,或者说进行加法运算。不过,当使用指针时,我们还可以这么做:交换两个指针的指向,而不是直接交换指针所指向的值。
代码如下:
根据输出可以看到,在没有交换指针指向时,ptr1指向0x00EFFC98,而ptr2指向0x00EFFC8C,在交换指针指向后,ptr1指向0x00EFFC8C,ptr2指向了0x00EFFC98。
![](https://img-blog.csdn.net/20160724113440775)
除此之外,指针的指针在队列方面还有非常便捷的应用,而这也是Linus所推崇的使用指针的方式来遍历队列,可以参考这里This persons don’t understand pointers。在这篇文章里,Linus认为正确使用指针遍历队列的做法应该是使用指针的指针,而不是按照一般教科书那样再使用一个prev指针。另外,还可以看看StackoverFlow的解释:Using pointers to remove itme from a singly-linked list
在这里,贴一下我Stackoverlfow上排名第一答案的理解,先把Linus版本代码贴一下:
首先,执行语句:
然后,随着不断的遍历链表,你就通过下面这个语句来移动“游标”
然后,原作者说,通过这样的方式,你就始终可以追踪你是从哪里来的,并且修改其实的指针(This way, you always keep track of the point where “you come from” and can modify the pointer living there.)
对于,我贴上我自己的理解,先上张图:
![](https://img-blog.csdn.net/20160724154311085)
比如,对于链表1->2->3->4->5。那么从图可以看出,节点1的地址为10(省略前部分),节点2的地址为30。。剩下的可以自己看head所在的地址。在循环还未开始前,*pp的值是节点1的值,而这时pp的值不重要。随着循环不断的进行,执行了语句:
这样,就把节点的next指针的地址赋给了pp,而next指针指向的是下一个节点,所以*pp的就是下一个节点的地址。因为,pp的值就可以表示当前你所在的位置(除了第一个值除外),而*pp的值这反映了当前要处理哪个节点。所以,当找到要删除的节点,就可以执行语句:
执行这条语句的结果就是把next指向当前节点的下一个节点,另外pp的值反映这个next指针的位置。于是,当前节点就被顺利的删除了。
最后,看看该如何解决这道LeetCode:Delete Node in linked list
这是我的代码:
和上面不同的是,这里只知道当前需要删除的节点、P和不在尾部的信息,所以我们不能直接把这个节点删除掉,而是先把P的下一个节点的值赋给P,接着把P的下一个节点删除掉(利用了节点不在尾部的信息)。
另外,其实完全可以不需要再申明一个指针p,而只利用节点node。
代码如下:
#include<iostream> using namespace std; void swap(int **ptr1, int **ptr2) { int *temp = *ptr1; *ptr1 = *ptr2; *ptr2 = temp; } int main() { int a = 5; int b = 8; int* ptr1 = &a; int *ptr2 = &b; cout <<" "<< ptr1 << " " << ptr2 << endl; swap(&ptr1, &ptr2); cout << "After swapping ----------" << endl; cout <<" "<< ptr1 << " " << ptr2 << endl; cin.get(); }
根据输出可以看到,在没有交换指针指向时,ptr1指向0x00EFFC98,而ptr2指向0x00EFFC8C,在交换指针指向后,ptr1指向0x00EFFC8C,ptr2指向了0x00EFFC98。
除此之外,指针的指针在队列方面还有非常便捷的应用,而这也是Linus所推崇的使用指针的方式来遍历队列,可以参考这里This persons don’t understand pointers。在这篇文章里,Linus认为正确使用指针遍历队列的做法应该是使用指针的指针,而不是按照一般教科书那样再使用一个prev指针。另外,还可以看看StackoverFlow的解释:Using pointers to remove itme from a singly-linked list
在这里,贴一下我Stackoverlfow上排名第一答案的理解,先把Linus版本代码贴一下:
/* LINUS VERSION */ ll **pp = &list_head; while (*pp != NULL) { if ((*pp)->value == REMOVE) { (*pp) = (*pp)->next; } else { pp = &((*pp)->next); } //这里没有free操作
首先,执行语句:
pp = &list_head;
然后,随着不断的遍历链表,你就通过下面这个语句来移动“游标”
pp = &((*pp)->next);
然后,原作者说,通过这样的方式,你就始终可以追踪你是从哪里来的,并且修改其实的指针(This way, you always keep track of the point where “you come from” and can modify the pointer living there.)
对于,我贴上我自己的理解,先上张图:
比如,对于链表1->2->3->4->5。那么从图可以看出,节点1的地址为10(省略前部分),节点2的地址为30。。剩下的可以自己看head所在的地址。在循环还未开始前,*pp的值是节点1的值,而这时pp的值不重要。随着循环不断的进行,执行了语句:
pp=&((*pp)->next)
这样,就把节点的next指针的地址赋给了pp,而next指针指向的是下一个节点,所以*pp的就是下一个节点的地址。因为,pp的值就可以表示当前你所在的位置(除了第一个值除外),而*pp的值这反映了当前要处理哪个节点。所以,当找到要删除的节点,就可以执行语句:
*pp = entry->next
执行这条语句的结果就是把next指向当前节点的下一个节点,另外pp的值反映这个next指针的位置。于是,当前节点就被顺利的删除了。
最后,看看该如何解决这道LeetCode:Delete Node in linked list
这是我的代码:
void deleteNode(ListNode *node) { ListNode** p = &node; **p = *((*p)->next); }
和上面不同的是,这里只知道当前需要删除的节点、P和不在尾部的信息,所以我们不能直接把这个节点删除掉,而是先把P的下一个节点的值赋给P,接着把P的下一个节点删除掉(利用了节点不在尾部的信息)。
另外,其实完全可以不需要再申明一个指针p,而只利用节点node。
相关文章推荐
- (转)IC验证概述
- chapter 1 let 和 const
- JS中数组的常见用法
- Pycharm 2016激活码
- Tableau 如何计算增长(去年及上个月或之前月份的)值
- 144. Binary Tree Preorder Traversal
- SDUT 2141 数据结构实验图论一:基于邻接矩阵的广度优先搜索遍历
- JSP技术(二)——JSP指令
- PAT 1016 Mice and Rice (25)
- 超级表格创始人中学时代揭秘
- ubuntu中source insight打不开,报错pagefault的解决方法
- DOM
- 《浪潮之巅》观后感
- poj 1201 Intervals [差分约束]
- Python之Pycharm常用快捷键
- 7.22号布置的作业
- IO - 同步,异步,阻塞,非阻塞
- UDP协议点对点(P2P)通讯(或者说NAT穿越)实例
- 盒子模型简介
- ubuntu 上查看内存信息