4

二级指针的作用详解

 1 year ago
source link: https://www.leftpocket.cn/post/cpp/secondary_pointer/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

二级指针的作用详解

2021-11-21 约 1605 字 预计阅读 4 分钟 16 次阅读

原文地址:码农在新加坡的个人博客

在如下的A指向B、B指向C的指向关系中:

C是"一段内容",比如你用malloc或者new分配了一块内存,然后塞进去"一段内容",那就是C了。C的起始地址是 0x00000008

B是一个指针变量,其中存放着C的地址,但是B也要占空间的啊,所以B也有地址,B的起始地址是 0x00000004,但是B内存中存放的是C的地址,所以B里面的内容就是 0x00000008

那么到此为止都比较好理解:

B= 0x00000008;  //B的内容 
*B = "一段内容";  //B解引用,也就是B指针指向的C的值
&B = 0x00000004;  //B取地址,B的地址是0x00000004

pic

那么,再来看A:

A是二级指针变量,其中存放着B的地址 0x00000004,A也有地址,是 0x00000000;

*A = B= 0x00000008;  //A解引用也就是B的内容 
**A = *B = "一段内容";  //B解引用,也就是B指针指向的C的值
A = &B = 0x00000004;  //A存的是B的地址,B的地址是0x00000004
&A = 0x00000000;  //A取地址

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

看看下面一段代码:有两个变量a,b,指针q,q指向a,我们想让q指向b,在函数里面实现。

1.先看看一级指针的实现

#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;
}

这么写有什么问题?为什么*q不等于100?我们看一下输出便知:

&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

我们看输出:

note:1->a,b,q都有一个地址.

note:2->q指向a.

note:3->我们发现参数p的地址变了,跟q不一样了,是的参数传递是制作了一个副本,也就是p和q不是同一个指针,但是指向的地址0x0032F000(a的地址)还是不变的.

note:4->p重新指向b.

note:5->退出函数,p的修改并不会对q造成影响。

编译器总是要为函数的每个参数制作临时副本,指针参数p的副本是 p,编译器使 p = q(但是&p != &q,也就是他们并不在同一块内存地址,只是他们的内容一样,都是a的地址)。如果函数体内的程序修改了p的内容(比如在这里它指向b)。在本例中,p申请了新的内存,只是把 p所指的内存地址改变了(变成了b的地址,但是q指向的内存地址没有影响),所以在这里并不影响函数外的指针q。

这就需要二级指针操作:

2.二级指针操作

#include<iostream>

using namespace std;

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

void func(int **p)  //2
{
	cout<<"func:&p="<<&p<<",p="<<p<<endl;
	*p = &b;  //3
	cout<<"func:&p="<<&p<<",p="<<p<<endl;
}


int main()
{
	cout<<"&a="<<&a<<",&b="<<&b<<",&q="<<&q<<endl;
	q = &a;
	cout<<"*q="<<*q<<",q="<<q<<",&q="<<&q<<endl;
	func(&q);  //1
	cout<<"*q="<<*q<<",q="<<q<<",&q="<<&q<<endl;

	system("pause");
	return 0;
}

这里只改了三个地方,变成传二级指针。我们再看:

因为传了指针q的地址(二级指针**p)到函数,所以二级指针拷贝(拷贝的是p,一级指针中拷贝的是q所以才有问题),(拷贝了指针但是指针内容也就是指针所指向的地址是不变的)所以它还是指向一级指针q(*p = q)。在这里无论拷贝多少次,它依然指向q,那么 *p = &b;自然的就是 q = &b;了。

3.再看一个例子:

我们代码中以二级指针作为参数比较常见的是,定义了一个指针 MyClass *ptr=NULL,在函数内对指针赋值 *ptr=malloc(…),函数结束后指针依然有效.这个时候就必须要用二级指针作为参数 func(MyClass **p,…),一级指针为什么不行上面说了。

void  my_malloc(char **s)  
{  
	*s=(char*)malloc(100);  
}  
 
void  main()  
{  
	char  *p=NULL;  
	my_malloc(&p);
	//do something
	if(p)
		free(p);  
}

这里给指针p分配内存,do something,然后 free(p),如果用一级指针,那么就相当于给一个p的拷贝s分配内存,p依然没分配内存,用二级指针之后,才对p分配了内存。

<全文完>

欢迎关注我的微信公众号:码农在新加坡,有更多好的技术分享。

pic

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK