1. 程式人生 > >c++ 筆記,->理解,指標的引用(*&)與指標的指標(**)

c++ 筆記,->理解,指標的引用(*&)與指標的指標(**)

一:->理解
網上百度看到的,說的很好,分享一下https://zhidao.baidu.com/question/143562807.html
->是一個整體,它是用於指向結構體、C++中的class等含有子資料的指標用來取子資料。換種說法,如果我們在C語言中定義了一個結構體,然後申明一個指標指向這個結構體,那麼我們要用指標取出結構體中的資料,就要用到“->”.
舉個例子:
struct Data
{
int a,b,c;
}; /*定義結構體*/
struct Data * p;/*定義結構體指標*/
struct Data A = {1,2,3};/*宣告變數A*/
int x;/*宣告一個變數x*/
p = &A ; /*讓p指向A*/
x = p->a;/*這句話的意思就是取出p所指向的結構體中包含的資料項a賦值給x*/
/*由於此時p指向A,因而 p->a == A.a,也就是1*/

對於一開始的問題 p = p->next;這應該出現在C語言的連結串列,這裡的next應該是一個與p同類型的結構體指標,其定義格式應該是:
struct Data
{
int a;
struct Data * next;
};/*定義結構體*/
…………
main()
{
struct Data * p;/*宣告指標變數p*/
……
p = p->next;/*將next中的值賦給p*/
}
連結串列指標是C語言的一個難點,但也是重點,學懂了非常有用。要仔細講就必須先講變數、指標。
什麼是變數?所謂變數,不要淺顯的認為會變得量就是變數。套用我們院長的問話:“教室變不變?”變,因為每天有不同的人在裡面上課,但又不變,因為教室始終在那,沒有變大或變小。這就是變數:有一個不變的地址和一塊可變的儲存空間。正常情況下,我們只看到變數這個房間裡面的東西,也就是其內容,但不會關注變數的地址,但是C語言的指標,就是這個房間的地址。我們宣告變數就相當於蓋了間房子存放東西,我們可以直接觀看房子裡的東西,而宣告指標,就是相當於獲得了一個
定位器
,當用指標指向某個變數時,就是用指標給變數定位,以後我們就可以用指標找到他所“跟蹤”的變數並可以獲得裡面的內容。
那結構體呢?結構體就相當於是有好幾個房子組成的別墅,幾個房子繫結在一起使用。假設現在有很多這種別墅分佈在一個大迷宮裡,每間別墅裡都有一間房子。裡面放了另一個別墅的位置資訊,現在你手拿定位器找到了第一棟別墅,從裡面得到了你想要的東西(連結串列的資料部分),然後把下一棟別墅的位置計入你的定位器(p = p->next),再走向下一棟別墅……如此走下去,知道走到某地下一棟別墅資訊沒有了(p->next == NULL),你的旅行結束。這就是連結串列一次遍歷的過程。現在你能明白 p=p->next的含義了吧!
轉:http://www.cppblog.com/doing5552/archive/2010/09/28/127994.html
在下列函式宣告中,為什麼要同時使用*和&符號?以及什麼場合使用這種宣告方式? 
  void func1( MYCLASS *&pBuildingElement ); 

  論壇中經常有人問到這樣的問題。本文試圖通過一些實際的指標使用經驗來解釋這個問題。
仔細看一下這種宣告方式,確實有點讓人迷惑。在某種意義上,"*"和"&"是意思相對的兩個東西,把它們放在一起有什麼意義呢?。為了理解指標的這種做法,我們先複習一下C/C++程式設計中無所不在的指標概念。我們都知道MYCLASS*的意思:指向某個物件的指標,此物件的型別為MYCLASS。 Void func1(MYCLASS *pMyClass); 


// 例如: MYCLASS* p = new MYCLASS;
func1(p); 
上面這段程式碼的這種處理方法想必誰都用過,建立一個MYCLASS物件,然後將它傳入func1函式。現在假設此函式要修改pMyClass: void func1(MYCLASS *pMyClass)
{
DoSomething(pMyClass);
pMyClass = // 其它物件的指標


  第二條語句在函式過程中只修改了pMyClass的值。並沒有修改呼叫者的變數p的值。如果p指向某個位於地址0x008a00的物件,當func1返回時,它仍然指向這個特定的物件。(除非func1有bug將堆弄亂了,完全有這種可能。)

  現在假設你想要在func1中修改p的值。這是你的權利。呼叫者傳入一個指標,然後函式給這個指標賦值。以往一般都是傳雙指標,即指標的指標,例如,CMyClass**。


MYCLASS* p = NULL;
func1(&p);

void func1(MYCLASS** pMyClass);
{
*pMyClass = new MYCLASS;
……
}


  呼叫func1之後,p指向新的物件。在COM程式設計中,你到處都會碰到這樣的用法--例如在查詢物件介面的QueryInterface函式中:


interface ISomeInterface { 
HRESULT QueryInterface(IID &iid, void** ppvObj); 
…… 
}; 
LPSOMEINTERFACE p=NULL; 
pOb->QueryInterface(IID_SOMEINTERFACE, &p);  

  此處,p是SOMEINTERFACE型別的指標,所以&p便是指標的指標,在QueryInterface返回的時候,如果呼叫成功,則變數p包含一個指向新的介面的指標。

  如果你理解指標的指標,那麼你肯定就理解指標引用,因為它們完全是一回事。如果你象下面這樣宣告函式:


void func1(MYCLASS *&pMyClass);
{
pMyClass = new MYCLASS; 
……


  其實,它和前面所講得指標的指標例子是一碼事,只是語法有所不同。傳遞的時候不用傳p的地址&p,而是直接傳p本身:

  MYCLASS* p = NULL;
  func1(p);

  在呼叫之後,p指向一個新的物件。一般來講,引用的原理或多或少就象一個指標,從語法上看它就是一個普通變數。所以只要你碰到*&,就應該想到**。也就是說這個函式修改或可能修改呼叫者的指標,而呼叫者象普通變數一樣傳遞這個指標,不使用地址操作符&。

  至於說什麼場合要使用這種方法,我會說,極少。MFC在其集合類中用到了它--例如,CObList,它是一個Cobjects指標列表。



Class CObList : public Cobject {
……

// 獲取/修改指定位置的元素
Cobject*& GetAt(POSITION position);
Cobject* GetAt(POSITION position) const;
};


  這裡有兩個GetAt函式,功能都是獲取給定位置的元素。區別何在呢?

  區別在於一個讓你修改列表中的物件,另一個則不行。所以如果你寫成下面這樣: Cobject* pObj = mylist.GetAt(pos);

  則pObj是列表中某個物件的指標,如果接著改變pObj的值: pObj = pSomeOtherObj;

  這並改變不了在位置pos處的物件地址,而僅僅是改變了變數pObj。但是,如果你寫成下面這樣: Cobject*& rpObj = mylist.GetAt(pos);

  現在,rpObj是引用一個列表中的物件的指標,所以當改變rpObj時,也會改變列表中位置pos處的物件地址--換句話說,替代了這個物件。這就是為什麼CObList會有兩個GetAt函式的緣故。一個可以修改指標的值,另一個則不能。注意我在此說的是指標,不是物件本身。這兩個函式都可以修改物件,但只有*&版本可以替代物件。 

  在C/C++中引用是很重要的,同時也是高效的處理手段。所以要想成為C/C++高手,對引用的概念沒有透徹的理解和熟練的應用是不行的。