close

<article class="mx-1 my-1">
<h3>目錄</h3>

<ul>
    <li><a href="#pointer/reference的宣告/定義式">pointer / reference的宣告/定義式</a></li>
    <li><a href="#一個int被pointer所指">int *p:一個int被pointer所指</a></li>
    <li><a href="#一個pointer被pointer所指">int **pp:一個pointer被pointer所指</a></li>
    <li><a href="#一個int被reference所參照">int &r:一個int被reference所參照</a></li>
    <li><a href="#一個pointer被reference所參照">int *&pr:一個pointer被reference所參照</a></li>
    <li><a href="#%E7%B8%BD%E7%B5%90">總結</a></li>
</ul>
<h3>正文</h3>

<h4 id="pointer/reference的宣告/定義式">pointer / reference的宣告/定義式</h4>
pointer可以分為宣告與定義式;reference不行,其宣告的地方即定義的地方
<pre>int main() {
    int i = 3;
    int* pi = &i;
    pi2 = &i;
    int* pi2 = nullptr;

    int& ri = i;
//  ri = i;       // 語法錯誤,reference不得重新定義
//  int& ri2;     // 語法錯誤,reference必須在宣告時,進行定義

    return 0;
}
</pre><!--more-->
函式呼叫的方式也是一樣的:
<pre>void ppp(int *pi, int *pi2 = nullptr) {
    // ok,pointer可以重新被定義,當然也可以設定初始值
}

void rrr(int &ri) {
    // ok,reference必須被函式呼叫時一併初始化,然而因為不得重新定義,當然不能設定初始值
}

int main() {
    int i = 0, j;

    ppp(&i);
    ppp((int *)&i);
    ppp(&i, &j);

    rrr(i);
//  rrr((int)i);  // 語法錯誤,參數為prvalue,ri必須為lvalue[3]
    rrr(j);       // ok,ri指的初始化是「將某個變數的位址初始化給ri」,該變數有無初始化無妨

    return 0;
}
</pre>
*以下的解釋皆以第一個呼叫的函式傳遞的變數來說明,其餘請舉一反三
<h4 id="一個int被pointer所指">一個int被pointer所指</h4>
這邊的*告知程式要新增一個區域的指標變數(在此函式內),來儲存傳遞進來的位址
<pre>void changeValueByPointer(int *p) {
    cout << *p << endl;    // p所儲存的變數——一個位址,其上面儲存的值,等同於i的值

    cout << p << endl;     // p所儲存的變數(一個位址),等同於i的位址

    cout << &p << endl;    // 區域暫時變數本身的位址
    
    *p = 1;                // 設定p所儲存的指標——一個位址,其上面儲存的值,等同於i的值,為1

    p = nullptr;           // 僅僅設定區域暫時變數p所儲存的位址,為nullptr
}

int main() {
    int i = 3;
    int *pi = &i;
    int **ppi = π
    cout << &i << endl;
    cout << &pi << endl;
    cout << &ppi << endl;
    cout << endl;

    changeValueByPointer(&i);
//  changeValueByPointer(pi);
//  changeValueByPointer(*ppi);

    return 0;
}
</pre>
然而使用reference的方式與原先的指標使用方式跟上面例子一樣,是相同的:
<h4 id="一個pointer被pointer所指">一個pointer被pointer所指</h4>
<pre>void changePointerByPointer(int **pp) {
    cout << **pp << endl;   // 3,等同於i

    cout << *pp << endl;    // pp儲存的位址——是個指標,其上面儲存的位址,等同於i的位址

    cout << pp << endl;     // pp儲存的位址,等同於pi的位址

    cout << &pp << endl;    // pp自己的位址,pp是個區域暫時變數
    
    **pp = 1;               // 設定i為1

    *pp = nullptr;          // 設定pp儲存的位址——是個指標,其上面儲存的位址的位址,也就是i的位址,為nullptr

    pp = nullptr;           // 僅僅設定區域暫時變數pp儲存的位址,為nullptr
}

int main() {
    int i = 3;
    int *pi = &i;
    int **ppi = π
    cout << &i << endl;
    cout << &pi << endl;
    cout << &ppi << endl;
    cout << endl;

    changePointerByPointer(&pi);
//  changePointerByPointer(ppi);
    
    return 0;
}
</pre>
<h4 id="一個int被reference所參照">一個int被reference所參照</h4>
這邊的&告知程式r是某個傳遞進來的變數的別名,使用r等同於使用傳遞進來的變數
<pre>void changeValueByReference(int &r) {
    cout << r << endl      // 不同於指標,對r做事情,等同於對i做事情,請當它是個別名
    
    cout << &r << endl;    // 取得r的位址,等同於i的位址

    r = 1;                 // 設定r為1,等同於設定i為1

    // 不同於指標,reference只是個別名,不可以被重新指定,且只能在宣告時同時指定
}

int main() {
    int i = 3;
    int *pi = &i;
    int **ppi = π
    cout << &i << endl;
    cout << &pi << endl;
    cout << &ppi << endl;
    cout << endl;
   
    changeValueByReference(i);
//  changeValueByReference(*pi);
//  changeValueByReference(**ppi);

    return 0;
}
</pre>
<h4 id="一個pointer被reference所參照">一個pointer被reference所參照</h4>
<pre>void changePointerByReference(int *& pr) {
    cout << *pr << endl;    // 不同於int **pp,這邊對pr做事情,等同於對pi做事情,
                            // *pr等同於*pi,等同於i的值

    cout << pr << endl;     // pi儲存的值,等同於i的位址

    cout << &pr << endl;    // pr本身的位址,等同於pi本身的位址
    
    *pr = 1;                // 設定pr所儲存的位址上面的值,等同於*pi,等同於i,為1

    pr = nullptr;           // 設定pr所儲存的位址,等同於pi,為nullptr
}

int main() {
    int i = 3;
    int *pi = &i;
    int **ppi = π
    cout << &i << endl;
    cout << &pi << endl;
    cout << &ppi << endl;
    cout << endl;
  
    changePointerByReference(pi);
    changePointerByReference(*ppi);
    
    return 0;
}
</pre>
<h4 id="總結">總結</h4>
pointer指向pointer,與pointer的reference,基本上對於指向之pointer所指之物可處理的事情是相同的,但對指向的pointer本身,由於reference只能初始化之,不能更改其位址,所以有著很大的區別

只要記住以下幾點,基本上就能了解各別的意義:

pointer:
<ol>
    <li>操作pointer,都隔一層*,因為pointer都儲存一個位址,利用*才能對該位址所對應的變數操作</li>
    <li>如同上一點,因為區域暫時變數的指標需要儲存一個值,我們在呼叫這種函式(int *p / int **pp)時,需要使用&取址運算子,提領位址傳遞</li>
    <li>操作pointer,</li>
    <li>可以先宣告一個指標,其後再定義,但建議先設定為nullptr[2]</li>
</ol>
reference:
<ol>
    <li>操作reference,都像操作原本的變數一樣,你可以將reference當個別名</li>
    <li>reference,必須於initializaer指定,且其後不得更改[2]</li>
</ol>
<h3>參考資料</h3>

<ul>
    <li>The C++ Programming Language - Bjarne Stroustrup</li>
    <li><a href="https://stackoverflow.com/questions/57483/what-are-the-differences-between-a-pointer-variable-and-a-reference-variable-in?rq=1">pointer與reference的差別</a></li>
    <li><a href="http://www.iattempt.net/article/8">徹底了解lvalue與rvalue</a></li>
</ul>
</article>

arrow
arrow

    Ernest 發表在 痞客邦 留言(0) 人氣()