---
# System prepended metadata

title: 我們來"參考"一下
tags: [筆記]

---

# 我們來"參考"一下
[TOC]
## 參考是什麼？
參考是什麼？ 
參考，英文名字叫做Reference

簡單來說，大家都有被取綽號的經驗吧，像是：
我名字叫做張簡雲翔，有人會叫我張簡、雲翔、山豬、死胖子等 ~~(都好難聽Q)~~
當別人叫我的時候，就可能會叫上面的名字，我都會知道別人再叫我
不管你用哪個名詞叫我，我還是我
不會你叫我山豬，我就真的變成一隻山豬吧XD 


Reference有點像這種感覺
**就是一個變數，但是它有很多很多個名字**
換句話說
**一個變數，它除了自己的名字外，還有別名(Alias)**
我們來看段程式碼
```cpp=
#include<iostream>

using std::cout;
using std::endl;

int main(int argc,char* argv[])
{
    int n=0;
    int& rn=n;       //declar reference
    
    cout<<" n："<<n<<endl;
    cout<<"rn："<<rn<<endl;
    
    n=20;
    cout<<" n："<<n<<endl;
    cout<<"rn："<<rn<<endl;
    
    return 0;
}
```
上面這段程式碼，輸出的結果如下：
![](https://i.imgur.com/LGd6OlD.png)

你會發現，我剛剛上面的程式碼，我改的明明是n的值，但是rn也被改了
這個就是參考的威力 ~~(威利在哪裡)~~

你還會發現，上面的程式碼，出現了一個神奇的語法
> int& rn=n;

這段語法就是在進行宣告一個參考的動作
**我宣告一個參考叫做rn，這個東西是n的別名**

接下來，我們把上面的程式碼改一下，變成這樣
```cpp=
#include<iostream>

using std::cout;
using std::endl;

int main(int argc,char* argv[])
{
    int n=0;
    int& rn=n;        //declar reference
    int *p1,*p2;
    p1=&n; p2=&rn;
    
    cout<<" n的記憶體位置："<<p1<<endl;
    cout<<"rn的記憶體位置："<<p2<<endl;
       
    return 0;
}
```
結果變成這樣：
![](https://i.imgur.com/I1tTlKN.png)

你會發現，這時候無論是n還是rn的記憶體位置都是一樣的
可以證明，我無論再叫n還是rn都是在叫同一個記憶體位置
![](https://i.imgur.com/cekN5AL.png)

### 小結
所謂參考，就是一個變數，我們給他另外一個別名
無論叫它自己本來的名字，還是參考的名字，都是在講同一個記憶體位置


## 複習一下Pass by value/address
如果你學過Function，你對這兩個名詞應該都不陌生
如果你沒學過Function，或者完全忘記那是什麼，~~那你加油~~
我這邊就不贅述Function是什麼，不知道的，請你自己先去研究完再繼續看

### Pass by value
顧名思義，就是**傳值**
範例如下
```cpp=
#include <iostream>

using std::cout;
using std::endl;

int value(int);   //prototype
    
int main(int argc,char* argv[])
{
    int a=0,b=0;
    b=value(a);
    cout<<a<<'\t'<<b<<endl;
    return 0;
}

int value(int a)
{
    a=a+100;
    return a;
}
```

上述程式碼，結果如下
![](https://i.imgur.com/41TzXWX.png)

從上面的程式碼，你可以發現
今天我在main function ~(第9行到第15行)~裡面的a
跟在value這個function ~(第17行到第21行)~裡面的a
是不一樣的a ~~(好繞口)~~

這是因為，今天在**傳值**的時候
我是把一個數字傳過去，之後那邊再開一個記憶體空間來存它
所以當我value這個function結束後，value的a就會不見了
![](https://i.imgur.com/SSdtSpO.png)

### Pass by address
從名字上能看得出來，就是**傳址**
但畢竟遇到是要**傳址**，所以會跟指標扯上關係，所以我們先來複習一下指標
>int* p;

宣告一個整數指標做叫p
>p=&a;

＆是一個一元運算子，它又稱為取址運算子，用途是在取得跟在它後面的變數在記憶體中所儲存的空間的位置 ~~(真的很繞口)~~
所以說這句話的意思是，我對a取址放進p這個整數指標變數
>＊p+=100;

＊在這邊也是一個一元運算子，它是一個提領運算子，用途是在取得，這個指標所對應的資料型態大小的空間。

上面的語法就會提領p後面整數大小的空間
並對p所指向的空間，加100

上面講的有點饒口，我們再看一個例子
* Ex：
    >double a;
    >double *ptr=&a; 

    這個是一個**雙精度浮點數**指標變數p，裡面放a的位置

    >*ptr;
    
    這一行就會提領後面**雙精度浮點數大小**(8 bytes)的空間出來。

複習完指標了，那我們來看傳址的範例
```cpp=
#include <iostream>

using std::cout;
using std::endl;

void value(int*);   //prototype
    
int main(int argc,char* argv[])
{
    int a=0;
    int* p=&a;
    value(p);
    cout<<a<<endl;
    return 0;
}
void value(int* p)
{
    *p+=100;
}
```
結果如下
![](https://i.imgur.com/r117y23.png)

從上面的程式碼，你可以觀察到
a原本是0但是經過value(ｐ)這一行後，a卻變成了100
這代表在value這個function中，它改變了a的值
可是這個情況跟剛剛**傳值**感覺起來不一樣

這是因為，我們傳的東西，並不是一個數值，而是**一個指標**
我們利用指標去找同一塊記憶體位置，去進行運算，所以才會改變原本的數值
![](https://i.imgur.com/bsIpKsu.png)
### 小結
Pass by value 只有傳值過去，那邊的空間與這邊的空間都沒有關係
Pass by address 透過指標，去找同一塊記憶體空間，改變裡面的數值

## 來傳參考囉：Pass by reference
Pass by reference 是一種C沒有，C++才有的一種傳遞參數的方法
我私心覺得，它是一個很好用的方法
因為傳址的語法比較複雜，有時候會打錯

那什麼是Pass by reference呢？
我們先來看一段語法
```cpp=
#include <iostream>

using std::cout;
using std::endl;

void value(int&);   //prototype
    
int main(int argc,char* argv[])
{
    int a=0;
    value(a);
    cout<<a<<endl;
    return 0;
}
void value(int& ra)
{
    ra+=100;
}
```
結果長得像這樣
![](https://i.imgur.com/nzFAXej.png)

從上面語法你會發現，我既沒有用指標，也沒有回傳數值，但是我main function裡面的a還是被改變了
這個就是**傳參考**的方便之處

我自己會覺得，**傳參考**有點像傳值跟傳址的融合
語法像傳值但是行為像傳址

今天我在開頭的prototype中
> void value (int&);

已經先跟電腦說好，我等等接收的參數會是一個**參考**
然後我再呼叫這個function的時候
>value(a);

它就會進入value這個function
這時候的ra就是a在value這個function的參考/別名
既然它是a的別名，自然我在value中，呼叫ra就是在叫a
**但是ra這個名字，只能在value這個function中用**
就跟你有些綽號，特定的人才能叫一樣
![](https://i.imgur.com/GKrK8LP.png)

### 小結
Pass by reference是一種傳遞參數得方式
今天傳遞的東西是reference
被傳遞的參數，在這個function會有一個新的別名
這個別名只能在這個function中用


###### tags:`筆記`