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