iT邦幫忙

1

c/c++語言: 統整指標與參考新手常犯的錯誤,初學者請進

閱讀本文前,
小馬推薦你可以先閱讀我的上一篇文 c/c++語言: 超好懂的指標(pointer)與參考(reference),歡迎初學者
先對c++語言的指標參考有概念再讀這一篇,
相信學習起來更能如魚得水。

小馬致力於使自己的教學文可以讓新手看得簡單易懂,
如您對小馬的文章有什麼想法或建議歡迎留言哦

指標參考是c/c++語言中重要的觀念,
但由於概念上相對複雜,
新手在撰寫上容易出錯,
少走冤枉路,一同來看看指標參考容易出錯的地方吧

一、宣告多個指標(或參考)的方法

在c++中,宣告一個指標有兩種合法的寫法都是等價的:
<第一種寫法>

int* p; // 合法但容易誤導讀者

<第二種寫法>

int *p;

為何說第一種寫法較容易誤導讀者呢?
且聽小馬慢慢道來

我們知道,在c++裡面可以一次宣告多個變數,
譬如說

int a1, a2;

就是一次宣告兩個型別為int的變數,名稱分別為a1a2

所以若採用第一種寫法的話,
就容易誤解成int*可以套用至每個宣告多個變數的型別,
譬如說新手想要宣告兩個int型別的指標可能會這樣寫:

<錯誤寫法>

int* p1, p2; //p1是對int的一個指標,p2是一個int

但實際上,int* p1, p2;的意思為:

int* p1;
int p2;

p1是對int的一個指標,p2是一個int

<正確寫法>

int *p1, *p2; //p1和p2都是對int的指標

小馬建議宣告指標(或參考)變數採用第一種寫法,
直接將*(或&)緊貼在變數前不要有空格

二、不可用int去初始化一個int指標

因為int *儲存的是一個地址,
int去初始化一個int型別的指標是不合法的,
(以生活化的例子來想,假設「王大明(比喻int)住在台北市中正路100號(比喻int *)」,
那麼一個合法的地址應該是「台北市中正路100號」,而不會是「王大明」)
例如,

<錯誤寫法一>

int *p1 = 100; //錯誤: 無法將int 指定給一個指標

<錯誤寫法二>

int z = 0;
int *p =z; //錯誤: 無法將int 指定給一個指標(即便那個int恰好是0)

<特別的合法寫法>

int *p = 0; // 將指標設為空指標

在這個大原則的例外是可以寫int *p = 0;
這個宣告的意思是將p設為一個空指標(null pointer),
等價的寫法是int *p = NULL;
表示這個指標沒有指向任何物件

三、指標不用初始化,參考必須初始化

這是參考和指標語法上的差別,
我們可以這樣去使用指標:

int *p; //宣告變數p,型態是對int的指標
int a = 5;
p = &a; //需要用到時才賦值

我們可以在程式中宣告int *p;
正如同我們平常宣告的int i;double d;一樣,
僅僅宣告這個變數而不給初始值

參考本身並不是物件,
參考只是一個物件的別名(就像是我們幫「王大明」取綽號叫「小明」一樣),
參考本身必須綁定一個物件,
因此,
<錯誤寫法一>

int &r; //錯誤: 參考必須初始化

<錯誤寫法二>

int &r=8; //錯誤: 參考不能綁定常數

<正確寫法>

int i;
int &r=i; //正確,r是變數i的別名

四、指標和參考指向的對象需要是相同類型

在c++中有型別轉換的功能,
比如說當我們將一個double類型的變數指定給int的變數,
小數點部分就會無條件捨去

例如:

double pi = 3.14;
int i = pi; //合法,i的值為3

但是在指標或參考中則不能指向不同的類型

<錯誤寫法一>

double a = 3.14;
int *p = &a; //型別錯誤

<錯誤寫法二>

double a = 3.14;
int &r = a; //型別錯誤

小馬覺得可能的原因是這樣:
指標代表一個記憶體中的位置,
不同型態變數之間(如int, double)所需要的儲存空間大小往往也不同,
不同型態變數的運算也有所不同,
因此指標或參考指向的變數型別需要是正確的

五、指標可以改變指向的對象,參考不能改變參考的對象

指標可以改變指向的對象,
請看以下的程式碼:

#include <iostream>
using std::cout;
using std::endl;

int main()
{
    int a = 5, b = 3; //宣告兩個整數a, b
    int *p = &a; //令指標p指向a的位置
    p = &b; //把指標p改為指向b的位置
    *p = 2; //將指標p所指的內容(也就是b)改為2
    cout << a << " " << b << endl;
}

結果印出5 2
程式一開始指向a的位置,
再改為指向b的位置,
這時再去做*p = 2
就會修改b的內容而不會改到a

參考變數一經初始化則無法改變參考的對象,
請試判斷下面的程式碼會輸出什麼結果呢?

#include <iostream>
using std::cout;
using std::endl;

int main()
{
    int a = 5, b = 3; //宣告兩個整數a, b
    int &r = a; //宣告一個參考變數r,r是a的一個別名
    r = b;
    r = 2;
    cout << a << " " << b << endl;
}

你是不是感覺答案好像會印出5 2呢?
初學者可能會誤以為r = b;這行會將r改成綁定b這個物件,
參考變數是無法改變參考的對象的
(以生活化的例子來想,假設我們給「王大明」取了綽號叫「小明」,
那麼「小明」這個外號就只能代表「王大明」而不能代表其它人)

一旦宣告int &r = a;,那麼ra就是同一個物件了,
所以r = b;這行其實就想成是a = b;就行了,
b的內容是數字3,所以r = b;會將整數a改為3
下一行再做r = 2則將整數a改為2
因此結果會印出:
2 3

對指標與參考的教學就先到這邊啦,
指標的概念較難掌握,
即便有經驗的工程師也容易出錯,
可以多多練習以熟悉它們,
以下給個課後練習幫助大家釐清觀念哦

課後練習(歡迎於留言區討論答案)

定義

int i = 0, &r1 =i;
double d = 0, &r2 = d;

請問下列是否有哪個指定是無效的呢?試解釋原因
(a) r1 = 3.5;
(b) r2 = r1;
(c) i = r2;
(d) r1 = d;


尚未有邦友留言

立即登入留言