<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>