指標變數 - 丁培毅

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

本來高階程式語言中的指標, 也沒人說一定要用記憶體的位址來製作, (C/C++ ... 用來做為指標, 例如: 在使用陣列變數的時候, 陣列變數的index 變數 ... 指標變數 在撰寫此段說明的時候, 我忘記我已經寫過一遍了, 所以鬧了雙胞, 請參考另外的一份說明: 指標變數與動態配置 觀念應該是相同的, 但是解釋的角度和列舉的範例有一些不同, 我也是覺得很奇怪, 同樣的東西怎麼在不同的時間會寫出不同的東西呢? 不管怎樣, 請您多花一點時間欣賞了... 概說 指標變數常常會造成初學者的困擾, 尤其對於只想學習C語言中屬於高階的那一部份的同學而言, 更是很容易覺得位址可有可無, 不知道什麼是位址還是可以撰寫許多的程式, 不是嗎? 本來高階程式語言中的指標, 也沒人說一定要用記憶體的位址來製作, (C/C++語言中為了執行的效率才會這樣子做的), 指標的概念算是讓CPU在存取資料時中間多一層的間接緩衝, 例如下面這句話: 麻煩你到系辦找助教拿程式設計課程的講義 當然也可以說 麻煩你到系辦拿程式設計課程的講義 這兩種說法其實目的是一模一樣的, 可是你一定可以感覺到第一種說法的彈性, 系辦裡有好幾個助教, 你可以任找一個, 助教可以把講義收在任何一個地方, 但是你應該都可以透過助教的幫忙拿到講義, 對了! 就是為了增加程式的彈性, 所以我們使用間接的方法來存取資料(或是程式)。

抽象的指標變數概念: 指標是為了讓CPU間接地存取資料的 CPU最終存取資料的地方是資料變數,指標變數裡記錄著哪一個資料變數需要被 CPU用來存取資料,或者說CPU透過某一個指標變數可以去存取該指標變數內指向的那一個資料變數。

舉一個一般的例子: 有一個送貨員有一百個客戶輪流去收貨/送貨, 他每天能夠處理的客戶個數視客戶當天貨物的多少而定, 有時處理50個, 有時處理30個, 有時處理70個, 不管前一天處理了多少個客戶, 他每天的工作就是要從接下去的那個客戶開始, 於是他就在小貨車的前座上掛了一塊牌子, 上面用白板筆寫著下一個該去收送貨的客戶, 這塊牌子就是一個指標, 上面記錄著應該要處理的資料(貨物)放在哪裡。

任意一種能夠記錄"究竟是哪一個變數"的方法理論上都可以用來做為指標, 例如: 在使用陣列變數的時候, 陣列變數的index變數其實具有指標的功能, 告訴CPU參與運算的a[index]到底是第幾個變數。

在C/C++中為了增進執行碼的效率, 用資料變數在記憶体內的位址 做為指標。

如下節所述。

C/C++指標的語法 如何宣告一個指標變數: int*iPtr;//定義一個可以存放整數變數指標(位址)的變數 iPtr double*dPtr;//定義一個可以存放浮點變數指標(位址)的變數 dPtr 注意: *是一個單元(unary)的取值(dereferenceorindirection) 運算子(operator),功能是"將其後所接的運算式之數值算出,當成一個記憶体位址,並讀取該記憶体位址內 (適當格式)之資料做為此運算之結果"。

iPtr稱為整數指標變數,dPtr稱為浮點指標變數。

上面的定義是在定義iPtr為整數指標變數(把int*看成是一種變數的型態),但是你也可以把它想像成是在定義 *iPtr為整數,如下: int(*iPtr); 如此你更可以瞭解為什麼不另創一個型態叫做intptr來定義iPtr了。

如何使用指標變數: 任何一個變數的基本功能都是存放資料, 不同型態的變數之間最主要的差別就是所存放資料的意義及解釋方法是不同的。

存放資料在指標變數內: 在C/C++中指標變數要存放的資料是記憶体的位址, 例如: int*iPtr;intx;iPtr=&x;//存放位址資料到iPtr變數內 注意: &是一個單元(unary)的運算符號, 其後必須要是一個變數, 它的功能是"找出其後變數的位址, 做為該運算的結果" 讀取指標變數內資料: 相對應上面"存放資料"這種使用iPtr變數的模式, "讀取資料"是另一種使用iPtr變數的模式, 例如: int*iPtr1,*iPtr2; intx,y; iPtr1=&x iPtr2=iPtr1; scanf("%d",iPtr1);  //scanf("%d",&x);scanf("%d",iPtr2); printf("%p%p",iPtr1,&x);  //以十六進位印出iPtr1之內容 上面紅字的iPtr1就是在讀取iPtr1指標變數內的位址資料。

間接存取指標變數所指向資料變數內之資料 除了上面兩種使用方式之外, 指標變數更常看到的使用法是與*運算子結合來間接地存取資料變數內的資料, 如下: a.*iPtr1=20;  //在變數x內存放20這個數值資料 b.printf("%d",*iPtr2);//將變數x內的資料交給printf()函式以10進位整數方式列印出來 y=*iPtr2+20;  //將變數x內資料讀出加上20後存入變數y之中 上面a,b這兩個用法尤其以a特別容易混淆。

請注意一般在等號的左邊我們必須放一個變數, 例如: x=10; 這個x和在等號右邊或是別的地方出現的x是不一樣的, 例如: y=x*5+fabs(x); 上面這個敘述中出現的兩個x, CPU在處理時都是去x那個變數裡把資料抓出來, 但是前一個敘述裡變數x出現在等號的左邊時(所謂的lvalue), 就不再是將x裡的資料讀出來了。

應該解讀為CPU見到等號左邊的x時會"將x的位址找到, 以便在設定運算中存放等號右邊計算出來的數值", 再來看看前面的 *iPtr1=20; 這個敘述, iPtr1是個指標變數, 裡面存放著變數x的位址, *iPtr1很明顯地和前面討論x放在等號左邊或是等號右邊的情形類似, *iPtr1放在等號右邊的話, 就是將變數x內存放的資料讀出, 但是*iPtr1放在等號左邊時, CPU在由變數iPtr1中讀出變數x的位址後, 不去讀變數x內存放的資料, 而將該位址(變數x之位址)留下來準備在設定運算中存放等號右邊計算出來的數值。

你也可以把程式中出現*iPtr1的地方看成是一個變數, 這個變數是"iPtr1變數內記錄的記憶體位址所代表的變數", 在程式編譯的時候CPU沒有辦法確定這個變數到底是指哪一個變數, 必須等到程式執行的時候CPU才根據iPtr1 變數內的結果去確定*iPtr1這個變數到底是指哪一個, 這樣子的話程式的功能會突然增強了許多,本來x=10;這樣的敘述 在程式執行的過程中永遠只能在一個確定的變數x內存放10這樣的資料, 現在*iPtr1=10;這樣的敘述則可以把10這個資料存放在很多不同的變數裡, 完全看程式執行到這一列敘述時iPtr1這個變數裡存放著哪一個變數的位址來決定。

程式中為什麼需要有指標這種東西? 其理由如下: 可以動態配置/釋放記憶體 存取資料或是執行函式時有更多的彈性 可以透過指標變數(pointervariable)來間接存取資料 可以透過函式指標(functionpointer)來間接呼叫函式 製作有效率的資料結構(串列、樹狀結構...) 使用傳值(call-by-value)當作函式呼叫時參數傳遞的基本機制時, 傳遞一個指標進入函式的話, 可以讓函式裡直接更改主程式內的資料, 可以說是函式呼叫時另一種資料的傳遞方式。

如下例: doublemean(int,double[],double*); voidmain(void) { doublemean,variance; doublex[10]={1,2,3,4,5,6,7,8,9,10}; mean=mean(10,x,&variance); } doublemean(intnumItems,doublex[],double*pVariance) { doublesum=0.0; inti; for(i=0;i



請為這篇文章評分?