您的位置:首页 > 其它

指针的指针

2016-07-24 11:46 316 查看
从交换两个数谈起。一般地,如果我们要交换两个数,不论是是使用指针,还是直接使用对应的类型。要么引入一个临时变量,要么进行异或操作,或者说进行加法运算。不过,当使用指针时,我们还可以这么做:交换两个指针的指向,而不是直接交换指针所指向的值。

代码如下:

#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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: