2016年9月12日 星期一

給新手的C++教學 (上冊) - 13 - 5. 陣列就是指標,指標就是陣列

回到「給新手的C++教學 (上冊)」

回到「13. 額外語法 (Extra syntax)」

上一頁

當您讀到「陣列」這個單元時,大可將「宣告一個大小為n的陣列」理解成「讓電腦幫你一次宣告n個變數」
但是,事實真的是如此嗎?

當您宣告一個變數的時候,電腦會挪出一塊記憶體給你用,啊然後咧?
這就像您想要網購某個東西,在購物網站上點了「購買」按鈕、付了錢,然後就以為沒事了(?)
不對啊,你總要知道要去哪裡取貨吧!
因此,程式向電腦「訂購」了記憶體之後,電腦就要告訴程式「取貨地址」--也就是「記憶體編號」,或稱「指標」

當程式執行到「int a;」這一行,程式會向電腦訂購32位元記憶體,然後電腦會告訴程式這32位元記憶體的「指標」。程式會小心翼翼地把這個「指標」記好,這樣才能隨時去使用它訂購的32位元記憶體

然而,有一件殘酷的事實是:
「記住指標」這個動作會讓程式需要額外的static記憶體 (之後會學到甚麼是static記憶體)

那這樣的話,把「宣告一個大小為$n$的陣列」理解成「讓電腦幫你一次宣告$n$個變數」會有甚麼問題嗎?
注意到,與其「訂購$32$位元記憶體$n$次,並記住$n$個指標」,還有另一種更有效率的方式:
直接一次性地訂購$32n$位元記憶體 (恩對一條街被買下來了(?)),然後依照「門牌號碼」分配給每個變數各$32$位元記憶體

差別在哪?這時程式只需要記住1個指標 (而非$n$個),也就是那「$32n$位元記憶體」的指標
當程式要取得第$i$ ($1\leq i\leq n$) 個變數的指標時,只要將第1個變數的指標加上$32(i-1)$位元就好了

怎麼證明電腦真的在做這件事?
信不信,陣列的名稱可以直接當指標來用XD (?!)
當然,小莫還要示範給你看!




#include<cstdio>
int main()
{
    int a[10];
    a[0]=2;
    printf("%d\n",*a);
    a[0]=4;
    printf("%d\n",*a);
    return 0;
}
 
改變「a[0]」,「a指標」指到的記憶體所儲存的數值也跟著改變
如果還不熟悉指標的用法,可以參考之前的指標章節

陣列真的是指標耶!而且真的是陣列第一個元素的指標!

那麼,「陣列」等不等於「指標」呢?
為了確認這點,除了要確認「陣列就是指標」,我們還需要確認是不是「指標就是陣列」

要怎麼確認指標是不是陣列呢?
我們可以取「a陣列」的第一個元素的指標,看看這個指標能不能當作「a陣列」來用就好啦

#include<cstdio>
int main()
{
    int a[10];
    int *b=&a[0];
    b[0]=1;
    printf("%d\n",a[0]);
    b[9]=2;
    printf("%d\n",a[9]);
    b[0]=3;
    printf("%d\n",a[0]);
    b[9]=4;
    printf("%d\n",a[9]);
    return 0;
}
把b當作陣列來用,改變b的第i項,a的第i項也跟著改變
我們取a陣列的第1個元素「a[0]」,取它的指標儲存成「b」
可以發現,當我們硬把「b」當作陣列來用的時候,不僅沒有出事,「b」的行為也完全和「a」一模一樣!

所以,「陣列」=「指標」,是嗎?
當然~
很意外吧XD

例外狀況:
  1. 我們不能從指標來得知陣列的長度,但是從陣列的名字就可以 (可以用sizeof(a)/sizeof(a[0]))
  2. 二維或更多維的陣列無法用指標表示

下一頁

感謝:匿名網友
(版權所有 All copyright reserved)

2 則留言:

  1. 雖然一般情況下pointer和array可以通用 但也有不能的時候 比如說2D array就不能用pointer表示
    另外 可以從陣列名稱知道長度吧? 用sizeof應該可以?

    回覆刪除

歡迎留言或問問題~
若您的留言中包含程式碼,請參考這篇
如果留言不見了請別慌,那是因為被google誤判成垃圾留言,小莫會盡快將其手動還原