二級指針的作用詳解

原文地址:http://blog.csdn.net/majianfei1023/article/details/46629065

一、概念

在如下的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

那麼,再來看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是一級指針,保存的是a的地址;q是指向指針的指針(二級指針),保存的是一級指針(p)的地址;q的內容就是0xbfaca770,*q的值即q指向的內容0xbfaca776,即*q仍然是一個地址,也就是指針p的內容,即*q=p
 

二、使用

 

二級指針作爲函數參數的作用:在函數外部定義一個指針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分配了內存。 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章