# C++ 筆記 (Reference & Pointer) ###### tags: `C++` --- # Reference Reference 就像就像別名一樣,用來表示一個物件. Reference 並不會佔用額外的記憶體空間。所有在該Referemce上所定義的操作,皆同等於操作在該Reference所參考的物件上。Reference很適合被用來當作function的參數以及回傳的型別。 ```typescript= int a = 10; int& refa = a; refa++; cout << a << ", " << refa << endl; ``` output : ``` 11, 11 ``` --- :warning: _Reference 在宣告時必須被初始化,且後續不能被更動,這邊的更動是指後續不行將Reference 重新指向另個物件。_ ## Read-Only Reference Reference 參考一個const object時, 該reference 必須也要是const,但相反地,一個reference為const時,其所參考的物件並非必要const物件。 const reference為read-only,代表只能存取該參考的物件,沒辦法更改物件內容,const reference初始化可以為常數初始化。 ```typescript= const int a = 10; int& refa = a; // wrong, need to be const reference const int& refa = a; // OK ``` ```typescript= int a = 10; const int& refa = a; // OK ``` ```typescript= const float& pi = 3.1415926; // OK ``` --- ## Passing By Reference Passing by reference 可以利用reference或是pointer當作function的參數來達成。 參數化的reference,每當function被呼叫時,就會以傳進來的參數初始化該refernce,並可直接對該物件進行操作。 ```typescript= void addOne(int& a){a++;} int b = 10; addOne(b); // b = 11 ``` --- ### Comparing to passing by value 使用passing by reference的好處 _1. passing by reference 物件並不會複製一份, 也就是說當參數是一個龐大的物件時,使用passing by reference可節省記憶體且速度上也會提升_ _2. function可以實現回傳多變數,將想回傳的變數當作參數以passing by reference傳進去。_ _3. 若只是想讀取而非寫入時, 可以使用read-only refernece來當作參數。_ --- ## Returning Reference Reference也能當作回傳值來使用。 ```typescript= double& refMin(double& a, double& b){ return a <= b ? a : b; } int a = 1.2, b = 2.1; double y = double(a, b); // y = 1.2 ++double(a, b) // a = 2.2, b = 2.1 ++double(a, b) // a = 2.2, b = 3.1 double(a, b) = 10; // a = 10, b = 3.1 double(a, b) += 3; // a = 10, b = 6.1 ``` :warning:_但需要注意的是function所回傳的reference必須是在function結束後還存在的物件。_ ```typescript= double& refReturn(){ int a = 5; return a; } ``` _參數a在function結束後, 記憶體會被釋放, 故會出現 reference to stack memory associated with local variable_ 此warning。日後可能造成無法預期的結果。 若想避免修改到reference的物件,可將function type定義成read-only。 --- # Pointer Pointer參數會指向與其相同的資料型態的位址,宣告實則是使用 * 來表示。 Pointer跟Reference非常相似, 兩個皆參考記憶體。但是, pointer不只是別名而已, 而是一個物件,有著自己的記憶取區塊,該記憶體的內容則是其參考的物件的位址,故pointer後續可以指向新的物件位址。 --- ```typescript= double x, *px; px = &x; ``` ```graphviz digraph{ compound=True edge [fontname="times new roman", fontsize=12]; node [fontname="times new roman", fontsize=14]; subgraph core{ a [label="px"] [shape="box"] } subgraph core{ b [label="x"] [shape="box"] } subgraph core{ c [label="Address of px"] [shape="box"] } subgraph core{ d [label="Address of x =\n value of px"] [shape="box"] } subgraph core{ e [label="value of x"] [shape="box"] } a -> c [label="&px"] a -> d [label="px"] b -> d [label="&x"] b -> e [label="x\n*px"] } ``` - pointer 所佔用的記憶體皆是相同的,不管是int pointer, double pointer or long pointer. 在32-bit的系統下為4bytes, 64-bit下為8bytes. 當然,Pointer也能當作參數傳進function. ```typescript= void swap(int* a, int* b){ int tmp; tmp = *a; a* = b*; b* = tmp; } int a = 5, b = 10; swap(&a, &b); // a = 10, b = 5;' ``` --- ## Exercise 1 請寫出一個function circle(...),計算圓周長與面積,該function傳三個參數。 1. radius : double型態 (read-only reference). 2. circumference : reference to double型態. 3. area : reference to double型態. <p> <details><summary>Answer</summary><br/> ```cpp= const double pi = 3.1415926; void circle(const double& r, double& circum, double& area){ circum = 2 * pi * r; area = pi * r * r; } double r = 5, c, a; circle(r, c, a); // r = 5, c = 31.4159, a = 78.5398 ``` </details> </p> --- ## Exercise 2 請寫出一個function quadratic(...), 回傳是否有解(true or false),並將解設置在兩個變數上,參數總共有五個。 1. a : double型態,兩次方之係數 2. b : double型態,一次方之係數 3. c : double型態,常數係數 4. x1ptr : pointer of double, 第一個解 5. x2ptr : pointer of double, 第二個解 <p> <details><summary>Answer</summary><br/> ```cpp= #include <cmath> bool quadrratic(double a, double b, double c, double* x1ptr, double* x2ptr){ bool return_flag = false; double helper = b * b - 4 * a * c; if(helper >= 0){ return_flag = true; helper = sqrt(helper); x1ptr = (-b + helper) / (2 * a); x2ptr = (-b - helper) / (2 * a); } return return_flag; } ``` </details> </p> ### Reference <a href="http://www.lmpt.univ-tours.fr/~volkov/C++.pdf">C++ from scratch</a>