理解c/c++二级指针

二级指针的应用,链表的删除操作

二级指针

把握一个原则,将指针作为函数参数时,看是为了修改指针指向的值(传入指针即可),还是指针的值(传入二级指针)

在c/c++中,指针其实也是变量,它也有相应的地址,对指针取地址就得到了存储这个指针的地址

二级指针作为函数参数的作用:在函数外部定义一个指针p,在函数内给指针赋值,函数结束后对指针p生效,那么我们就需要二级指针。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include<iostream>  

using namespace std;

int a= 10;
int b = 100;
int *q;

void func(int *p)
{

cout<<"func:&p="<<&p<<",p="<<p<<endl; //note:3
p = &b;
cout<<"func:&p="<<&p<<",p="<<p<<endl; //note:4
}


int main()
{

cout<<"&a="<<&a<<",&b="<<&b<<",&q="<<&q<<endl; //note:1
q = &a;
cout<<"*q="<<*q<<",q="<<q<<",&q="<<&q<<endl; //note:2
func(q);
cout<<"*q="<<*q<<",q="<<q<<",&q="<<&q<<endl; //note:5

system("pause");
return 0;
}

输出结果为:

1
2
3
4
5
&a=0032F000,&b=0032F004,&q=0032F228
*q=10,q=0032F000,&q=0032F228
func:&p=0018FD24, p=0032F000
func:&p=0018FD24, p=0032F004
*q=10,q=0032F000,&q=0032F228

执行函数后,*q的值没有变成100;在上面可以看出,当把指针作为函数参数时,会产生一个临时变量,指向与传入指针相同的地址处。对这个临时指针的修改并不能修改实参指针的值。

另外的应用为:为一个指针分配空间,也就是修改了指针所指向的值,此时函数的参数要为二级指针

1
2
3
4
5
6
7
8
9
10
11
12
13
void  my_malloc(char **s)    
{

*s=(char*)malloc(100);
}

void main()
{

char *p=NULL;
my_malloc(&p);
//do something
if(p)
free(p);
}

下面看链表的例子
向链表中添加元素

1
2
3
4
5
6
7
8
9
10
11
12
13
void addToTail(ListNode **pHead, int val){
ListNode *temp = new ListNode(val);

if(*pHead == NULL){
*pHead = temp;
}else{
ListNode *p = *pHead;
while(p->next){
p = p->next;
}
p->next = temp;
}
}

Given a linked list, remove the nth node from the end of list and return its head.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode **pHead = &head;
ListNode *fast = head;
for(int i = 1; i < n; i++)
fast = fast->next;

while(fast->next){
fast = fast->next;
pHead = &((*pHead)->next);
}

*pHead = (*pHead)->next;
return head;
}
};

将上面的第11行换成

1
*pHead = (*pHead)->next

输入测试用例会得到

1
2
1->2->3->4->5
2

会得到5
自己一直不解,后来经过仔细分析,才发现,原来pHead一直保存的是指向头结点指针的地址,当用pHead = (pHead)->next修改时,实际上是改变了头结点的地址,将头结点的地址变成了头结点的下一个节点。

而使用pHead = &((*pHead)->next)是,实际上是将上述的二级指针变成了指向头结点的下一个节点的指针的地址。

类比一级指针的例子

1
2
3
int a = 1;
int b = 2;
int *p = &a;

两种方案
p = &b
这种实际上是将p指向了b地址将发生变化
*p = 2
这种并没有改变指针指向的地址,只是将这块地址指向的内存的值变成了2,实际上p指向的地址还是a得地址。但a的内容已经变化。

可以参考这篇文章二级指针的介绍