2017年6月5日 星期一

指針(point) 與 參考(ref) 有什麼不同之處

指針(point) 與 參考(ref) 有什麼不同之處

tags: C++ Concept2
本文所指的指針的指針指的是指標,個人覺得這樣比較好做區別
初學時時常讓人搞不清楚的兩個不同的東西,這邊提供幾個大原則做判斷
指針:可以儲存記憶體位置的型別
參考:就好像別名一樣可以完全等同於所指之物
比較特別的還有一種情況叫做(*\&)指針的參考,這又是什麼呢?

兩個符號的用法

分別是
  • *取址 reference
  • &取值 dereference
他們放在非宣告時的變數的前方,從英文可以看出他們具有相反的關係。
首先最讓人搞不清楚的是為什麼他們在宣告時有不同的關係,那根本就是不一樣意思了。
int* i;
int& a;
你把它當作別的東西來看直接把整串看做是一個型別。
我的意思是你不要這樣看int* i; 而直接是 int* i;
前者表示宣告一個指針容器,後者表示宣告一個別名,跟剛剛的*&完全是兩回事。
由此我也更推薦你使用 int* i; 而不是 int *i;這樣更容易表達。
除非你需要連續宣告,這就真的不得已了int *i, *j; 連續宣告時要個別指定。
回到剛剛的取址與取值簡單來說就是你現在有一個變數,它存在記憶體的某個地方,這個某個地方會用一串數值表示位置比如說 0x01
現在你手上拿到 p=0x01 你希望獲取他的數值就是使用取值 *p 獲取內容
你現在手上拿到 p=0; 你希望獲取他的地址就是使用取址 &p 獲取地址

地址的傳遞可以共同編輯

函式(包含main)內都有各自的空間,彼此是不同互相存取的除非你使用全域函式。
他就像一個公用櫃子一樣,只要你告訴別人我的東西放在幾號櫃子別人就可以來存取。
比如以下的代碼
int i=0;
int* p=&i;
現在p也可以修改i
*p = 1;
把它放到函式內就像這樣
void fun(int* p){
    *p = 1;
}
使用時就像這樣
fun(&i);

參考基本用法

底層裡面都是做指針的存取,使用方法怎麼區別可以這樣想像
參考就像一個不用輸入符號的指針
什麼意思呢,假設有一個指針為下
int i=0;
int* p=&i;
現在p也可以修改i
如果寫成參考就像這樣子
int i=0;
int& ali=i;
現在ali也可以修改i,現在操作ali就像在操作i
叫王小明的綽號 阿明 就像在叫王小明一樣。
放到函式可以省很多事情
void fun(int& p){
    p = 1;
}
使用時就像這樣
int i=0;
fun(i);
現在你在函式內的操作以及呼叫函式時的操作,全部都不用加上符號上了,是不是更好用呢?
或許你會在學到參考後一股腦地全部換參考,但其實他們之間大概有細微的差異

指針

  • 需要檢查有效性
  • 可以指向Null表示無效,也可以隨時更換指向的目標
  • 有指針的指針

參考

  • 不需檢查有效永遠有效
  • 不能換參考,且只能在宣告時給定目標
  • 沒有參考的參考
彙整出來的兩條守則:
  1. 不想付出檢查成本就用參考
  2. 需要更動指向的目標物或初始化為無效,只能用指針

活用參考與指針

很多時候他們是可以互相通用的,這可能不好記憶,透過練習題更容易熟悉,詳見以下的範例
有一個函式
  • 可以在函式內改他的值
  • 並使回傳的可以更改內容
看起來有些繞口,直接看代碼會比較好理解
要可以做到以下的樣板功能
int i;
fun(/*i*/);       //更改 i 的值
fun(/*i*/) += 10; //並加10
大致可以有以下四種做法,各字看一次,做一次應該10分鐘就可以入門參考與指針了
#include <iostream>
using namespace std;

int* fun1(int* i){
    *i = 1;
    return i;
}
int* fun2(int& i){
    i = 2;
    return &i;
}
int& fun3(int* i){
    *i = 3;
    return *i;
}
int& fun4(int& i){
    i = 4;
    return i;
}

int main() {
    int i=0;
    *fun1(&i) += 10;
    cout << "i=" << i << endl;
    *fun2(i) += 10;
    cout << "i=" << i << endl;
    fun3(&i) += 10;
    cout << "i=" << i << endl;
    fun4(i) += 10;
    cout << "i=" << i << endl;
    return 0;
}

沒有留言:

張貼留言