close

在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的頭開始分析。

image

一個錯誤的例子

#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的目的。 
  image

一個正確的例子(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也可以達到同樣目的。請先閱讀這篇:

[C++] Call by value、Call by pointer、Call by reference

一個正確的例子(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

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 丘猴子 的頭像
    丘猴子

    轉貼部落格

    丘猴子 發表在 痞客邦 留言(0) 人氣()