C語言: 超好懂的指標,初學者請進~ - 寫點科普Kopuchat

文章推薦指數: 80 %
投票人數:10人

等等,那C 語言中的指標是長什麼樣子? 讓我們來看看這段程式碼: void main(){ int a = 15; int b = 2; int c = 39; ... 跳至內容 程式教學>C/C++ 內容目錄 什麼是指標(Pointer) 指標變數(Pointervariable) 程式教學>C/C++ 內容目錄 什麼是指標(Pointer) 指標變數(Pointervariable) 指標(pointer)這個功能在C語言中有著非常重要的地位。

C語言中特有的指標,可以透過記憶體映射的方式直接控制硬體,這也是為什麼C語言在硬體系統特別強大的原因,包括資料結構(陣列/字串/鏈結串列)、系統程式(編譯器/作業系統)、演算法,都會進一步使用到。

但對於初學者來說,一開始無法釐清指標、導致後續指來指去,指到最後往往變成噩夢。

今天我們的目標,就是從頭開始把指標介紹的非常簡單。

  什麼是指標(Pointer) 這張照片叫「MilkyWayandStarryNightSky」,是一張看著便賞心悅目的美麗星空圖,當桌布做美工都適合。

如果你想要這張照片的話,最直接的辦法就是我給你這張照片的網址「https://www.goodfreephotos.com/astrophotography/milky-way-and-starry-night-sky.jpg.php」,讓你在網址上拿到這張照片。

    這和指標有什麼關係呢?概念很類似噢!只要我給你這個網址,你就可以藉由這個網址拿到這張照片,也就是說網址是指向這個資料的「指標」。

哦~原來資料的地址就是指標嘛,是不是非常簡單的概念呢? 等等,那C語言中的指標是長什麼樣子? 讓我們來看看這段程式碼: voidmain(){ inta=15; intb=2; intc=39; intd=180; inte=67; } 在這個程式碼中,我們宣告了五個變數。

以intb=2為例,在宣告好變數、程式開始執行後,會去記憶體中要一塊儲存空間,然後把2這個資料放進去。

還記得我們說過記憶體就像一個大櫃子、每個格子都有相對應的地址嗎?這個2的地址就是在記憶體中的某一個地方。

但我們說過,記憶體中一個格子的大小是1個byte,而一個int(整數型)的大小就占了4個byte,所以這邊寫的地址,是2這個整數所占的這一塊記憶體空間的起始地址。

從起始地址開始起算、共佔了4個格子,也就是4byte。

也就是說,當我們宣告一個變數時,總共會有三個要素:   程式會向記憶體要一塊空間來儲存變數值,所以這個儲存空間有一個起始位址。

再加上這個變數的名稱(b)與變數值(2)。

通常我們會把變數的位址,稱為「指向該變數的指標」。

在這邊需要特別注意的是,我講的是「指標」,而不是「指標變數」;這兩個是不同的東西。

拿一開始的照片作為對照例子,是不是很清楚呢? 但我們在宣告一個變數,比如宣告b的時候,要怎麼知道到底是跟記憶體要了哪一塊地址放這個b呢?怎麼樣才能看到這個變數的位址? 這邊就要介紹一下在C語言裡面,有個運算符號是用來「取址」,就是「&」。

怎麼做呢?請參考以下程式: #include intmain(void){ intb=2; printf("變數b的值:%d\n",b); printf("變數b的記憶體位址:%p\n",&b);//%p為印出地址的16進位表示法 return0; } 看一下在Terminal中編譯完的結果: 這個程式中,宣告了一個int整數變數b,並藉由印出「&b」的值,知道 b 所在的記憶體位址是0x7fff54a109c8(16進位表示法)。

從0x7fff54a109c8開始的4個byte都是b所配置到的記憶體空間,儲存了2這個值。

這時你一定想問:有地址要做什麼?我們宣告完變數後也用得好好的,沒事要它的地址幹嘛? 事實上我們拿到一個地址,都是為了要去到這個地址上、以抓取上面的變數。

(知道了朋友的地址,目的不就是要去拜訪他嗎?或就像我們利用網址去抓照片一樣) 但問題來了,怎麼樣能利用一個變數的地址、去拿到這個變數呢?直接把地址寫出來然後執行嗎? 答案是不行的。

我們要利用C語言中的另一個運算元「*」來做這件事。

#include intmain(void){ intb=2; printf("變數b的值:%d\n",b); printf("變數b的值:%d\n",*&b);//從這個地址中取出變數b的值 return0; } 來看看Output的結果: 奇怪,明明印出b變數的值,和「從b這個位址中取值」印出*&b,還不是一樣的答案?這樣的話為什麼要寫那麼多? 你說的沒錯。

事實上,「*&b」和「b」的意義是等價的。

  指標變數(Pointervariable) 講完了什麼叫指標後,接下來讓我們看看「指標變數」。

還記得我們說過,指標(Pointer)就是某變數的位址。

而這邊的指標變數(PointerVariable),則是用來存放指標的變數。

  案例中的pointer就是一個指標變數。

變數都是用來存放「值」的,而整數型變數int就是存整數、字元型變數char就是存字元。

所以這個指標變數就是用來存「地址」的變數。

也就是說,宣告一個指標變數,和一般宣告變數一樣,是跟記憶體要一個區域、存放這個變數的值。

只是這個變數的型別是指標。

另外,由於pointer中存的地址是變數b的值,因此我們又把pointer稱為「變數b的指標變數」。

這些概念非常的簡單,只是一定要弄清楚。

接下來你可能會問:要怎麼去宣告一個指標變數呢? 我們可以採用「*」這個運算符號。

int*pointer pointer表示這個變數的名稱,而*表示pointer這個變數是個指標。

等等,那int代表什麼意思?星星符號運算元*不就說是個指標了嗎? int代表這個指標變數指向的變數的類型。

…你在說什麼在繞口令嗎? 直接看下圖吧! 具體來說的程式碼長這樣: intb; //跟記憶體要一塊區域稱為b,這塊區域專門放int型變數值 b=2; //把2這個值給變數b int*pointer; //跟記憶體要一塊區域稱為pointer,這塊區域專門放指向int型變數的指標(地址) pointer=&b; //把變數b的地址值給pointer,注意不能寫成pointer=b; 還記得「&」代表「把這個變數的地址取出來」的意思嗎?要注意,這邊絕對不能寫成pointer=b;,因為pointer是專門存放地址的變數。

如此一來,我們就稱「指標變數pointer指向了變數b」,是不是很好懂呢! 很多書上寫的有些模糊,初學者又還搞不清楚時,就會導致指標、指標變數、指標變數宣告等產生混亂。

接下來還想問個問題:能不能利用pointer去拿到它指向的b這個變數呢?當然可以。

這邊同樣要利用到*這個運算符號。

當我們跑完這個程式碼之後: intb=2; int*pointer=&b; 會發生這件事: 也就是說變數b在記憶體中對應了一塊儲存空間,而這塊儲存空間總有一個起始的地址。

所以pointer對應到的就是這個起始地址。

在這種狀況下,就可以用「*pointer」來拿到這個變數。

這裡的「*」,和宣告指標變數的int*pointer的意義不太一樣。

反而是和「&」相對應——「&」代表「取出地址」、「*」代表「取出內容」。

等等,那所謂的「*pointer取出的內容」指的到底是變數b、還是變數b的值2? 這兩個是不同的東西喔!變數b是這塊區域,2是值。

答案是:*pointer代表的就是變數b。

所以我們可以把*pointer當作變數b來使用。

直接看程式碼吧: #include intmain(void){ intb=2; int*pointer=&b; printf("變數b的值:%d\n",b); printf("變數b的地址:%p\n",&b); printf("pointer的值:%p\n",pointer); printf("\n");//換行 *pointer=100; printf("*pointer的值:%d\n",*pointer); printf("變數b的值:%d\n",b); printf("變數pointer的地址:%p\n",&pointer); return0; }   執行這段程式碼的結果: 我們可以看到一開始的變數b的值被設定為2,所以印出來也會是2。

然後用「&b」取出變數b的地址為「0x7fff551b49c8」。

由於&b的值被賦予給pointer,所以把pointer印出來後同樣也是「0x7fff551b49c8」。

由於我們說過*pointer就是其指向的變數b,所以在這邊我們試著把*pointer中的值改成100,然後印看看原有的變數b會不會跟著改變。

發現會欸!2被改成100了! 最後,由於存放pointer這個變數的地址,和變數b的地址不一樣,所以利用「&pointer」後,可發現地址「0x7fff551b49c0」和變數b的地址果然不一樣。

試著寫個小程式玩玩看: #include intmain(void){ inta,b,temp; int*p1,*p2; printf("請輸入a的值:"); scanf("%d",&a); printf("請輸入b的值:"); scanf("%d",&b); p1=&a; p2=&b; if(*p1



請為這篇文章評分?