在C語言裡,我們可以使用pointer指向一個實體,因此如果把實體變數的address傳到一個funtion的pointer,那就可以改變此pointer所指向的實體的值。
但是如果我們要改變的不是pointer所指向的實體的值,而是pointer本身的值,那就把pointer當作一種type,再把它的address傳到funtion的double pointer。以下將舉一個例子說明。
假設我們有一個function readData可以從網路抓取packet後,填到一個unsigned型態的的buffer(以pointer傳入),接著我們會使用一個function parse1來分析前半段的buffer,然後在使用function parse2來分析後半段的buffer。在parse的程式碼中,我們使用(buffer++) 來移動buffer的pointer,以利往下讀取資料。
在下面的程式碼中,我們在parse1和parse2都是使用unsigned *buffer來接住main裡的buffer的位址(假設在0x100),因此parse1和parse2接收到的pointer的值都是副本,也就是0x100。所以即使在parse1移動buffer pointer,也不會影響在main的buffer的位址。所以,當parse2呼叫時,傳入buffer pointer的值,依然是0x100,還是從buffer的頭開始分析。

一個錯誤的例子 |
#include <iostream> using namespace std; #define BUFFER_SIZE 10
void readData(unsigned *buffer, int size) // Ex:從網路讀取資料寫道buffer { for (int i = 0; i < size ; i++) { buffer[i] = i; } }
void parse1(unsigned *buffer, int size) // 開始第一階段parse讀取到的資訊 { for (int i = 0; i < size ; i++) { cout << "processing with parser1:" << *(buffer++) << endl; // 每讀取一個元素後,指標移動 } }
void parse2(unsigned *buffer, int size) // 希望從第一階段的parse後,繼續第二階段的parse { for (int i = 0; i < size ; i++) { cout << "processing with parser2:" << *(buffer++) << endl; } }
int main(void) { unsigned buffer[BUFFER_SIZE]; readData(buffer, BUFFER_SIZE); parse1(buffer,BUFFER_SIZE/2); parse2(buffer,BUFFER_SIZE/2); // 此時buffer的pointer,並不會從一半開始,還是原本的頭開始 return 0; /* output: processing with parser1:0 processing with parser1:1 processing with parser1:2 processing with parser1:3 processing with parser1:4 processing with parser2:0 processing with parser2:1 processing with parser2:2 processing with parser2:3 processing with parser2:4 */ }
|
我們可以使用pointer to pointer達到修改pointer的值的目的。方法如下:先使用 unsigned *p = buffer; 來複製一份buffer的address。因此p的值為0x100,並且假設p的address為0x500。然後在parse裡使用unsigned **buffer_p指向p,因使buffer_p的值為0x500。接著我們可以使用(*buffer_p)++來改變p的值,也就是p所指向的位置可以跟個改變。所以在parse1執行完後,p的值,就會改變成0x200,所以再把p的address給parse1後,buffer_p的值雖然一樣式0x500,但是buffer_p所指向的值就變成0x200。因此使用*((*buffer_p)++) 可以指向p,再指向buffer裡實體的unsigned變數。
Note,由於array的address不可以改,所以我們才需要一個p來記錄buffer的address,並且透過修改p的值來達到移動pointer的目的。

一個正確的例子(pointer to pointer) |
|
#include <iostream> using namespace std; #define BUFFER_SIZE 10
void readData(unsigned *buffer, int size) { for (int i = 0; i < size ; i++) { buffer[i] = i; } }
void parse1(unsigned **buffer_p, int size) { for (int i = 0; i < size ; i++) { cout << "processing with parser1:" << *((*buffer_p)++) << endl;; } }
void parse2(unsigned **buffer_p, int size) { for (int i = 0; i < size ; i++) { cout << "processing with parser2:" << *((*buffer_p)++) << endl;; } }
int main(void) { unsigned buffer[BUFFER_SIZE]; unsigned *p = buffer; readData(buffer, BUFFER_SIZE); parse1(&p,BUFFER_SIZE/2); parse2(&p,BUFFER_SIZE/2); return 0; /* output: processing with parser1:0 processing with parser1:1 processing with parser1:2 processing with parser1:3 processing with parser1:4 processing with parser2:5 processing with parser2:6 processing with parser2:7 processing with parser2:8 processing with parser2:9 */ }
|
如果你覺得看不習慣pointer to pointer,可以使用reference to pointer也可以達到同樣目的。請先閱讀這篇:
一個正確的例子(reference to pointer) |
|
#include <iostream> using namespace std; #define BUFFER_SIZE 10
void readData(unsigned *buffer, int size) { for (int i = 0; i < size ; i++) { buffer[i] = i; } }
void parse1(unsigned *&buffer, int size) { for (int i = 0; i < size ; i++) { cout << "processing with parser1:" << *(buffer++) << endl;; } }
void parse2(unsigned *&buffer, int size) { for (int i = 0; i < size ; i++) { cout << "processing with parser2:" << *(buffer++) << endl;; } }
int main(void) { unsigned buffer[BUFFER_SIZE]; unsigned *p = buffer; readData(buffer, BUFFER_SIZE); parse1(p,BUFFER_SIZE/2); parse2(p,BUFFER_SIZE/2); return 0; /* output: processing with parser1:0 processing with parser1:1 processing with parser1:2 processing with parser1:3 processing with parser1:4 processing with parser2:5 processing with parser2:6 processing with parser2:7 processing with parser2:8 processing with parser2:9 */ }
|
Read more: http://csie-tw.blogspot.com/2010/03/c-pointer-to-pointerreference-to.html#ixzz2C5nC80Dc