# NOTE:指標篇 contributed by < `yungchuan` > :::danger 你的提問呢?回顧你過去開發的程式,難道沒想到概念上有衝突或者激發出更多想法嗎? :notes: jserv ::: ## 核心概念 指標可以很複雜,也可以很簡單。我認為要真的弄懂指標其實只需要把握住它的核心概念:==記憶體位址==。當然並不是說只要知道指標代表記憶體位址就能治百病,必須還要搭配規格書上面介紹的指標各種的用法、使用限制等等。但是知道核心概念後,對於解讀複雜的程式碼會容易許多。 ## 型態 使用指標時,一定會遇到的事情就是:這個指標是指向什麼型態?在規格書中有提到: ```A pointer type may be derived from a function type, an object type, or an incomplete type, called the referenced type. C99[6.2.5]``` 這代表了指標能指向幾乎所有型態,連 incomplete type 都可以。而對指標而言,型態的意義就是==如何在定位到資料位址之後使用資料==。假設是一個整數指標 (int*) ,其在取出資料時就會以整數的格式將資料取出。如果這個資料並非整數,取出來的資料就會錯誤。 #### Incomplete Type >若一個型態在定義時並未給予一個明確的空間,則稱為 incomplete type 。而這種 incomplete type 不能建立一個物件,但是可以建立一個指標去指向此 incomplete type 。如下: ```Clike struct IncompleteType; struct IncompleteType x; //error struct IncompleteType *x; //a point to a incomplete type ``` ## void * void 最常使用在函式宣告中,意思是函式執行完不會回傳資料。而當 void 宣告成指標 void * 的時候,其意思變成單純的記憶體位址,也就是說 void * 跟其他的指標一樣是代表一段記憶體位址,但是指向的資料沒有、或者說不知道型態。而通常就必須靠程式撰寫者去==強制轉型==此指標,將它轉型成需要的資料型態再來使用。 ## 雙重指標? 基本上在寫程式的時候,時常可以看到 int **ptr; List **head; 等寫法,而很多人就直接順著念「雙重指標 (double pointer) 」了。但其實這不是一個正確的稱呼,而是應該稱為「指標的指標 (a pointer to a pointer) 」。畢竟「雙」有「對稱」的意義,而指標的指標有種接續的感覺,是不能並用的。就像我們不會稱兒子的兒子為雙胞胎吧? ## Pointers vs. Arrays * pointer 代表記憶體位址, array 代表一個連續的記憶體區段。 * 在函式的參數列上宣告 x[] 與 *x 的意思是相同的,皆為指標。 * [] 運算代表「位移後提領」,也就是說 x[4] = *(x + 4) = *(4 + x) = 4[x] 。 * 指標的位移是根據型態決定的。若一個型態在記憶體中為 4 byte ,那麼其位移一次就會移動 4 byte。 * 在 C 語言中,多維陣列的實作是靠一維陣列去實現的。在取值時會看給予的數值對應到的線性記憶體位址而將值取出。 ## Function Pointer 考慮以下程式碼 ```Clike void (*fptr)(); void test(); fptr = test; ``` * 直觀考慮, fptr 是一個函式的指標,可以記錄函式的位址。 * 在 C 的函式庫中,有一 qsort 宣告如下,可以看到其最後一個參數 ```int (*compar)(const void *, const void *);``` 即宣告為 function pointer ,其意義為 compar 這個 function pointer 會指向一個函式,此函式的功能為決定要排序的資料誰大誰小。所以在執行 qsort 時,會經由 compar 這個 function pointer 把資料傳給比較大小的函式,再經由回傳值來排序。 ```Clike void qsort(void *base, size_t nmenb, size_t size, int (*compar)(const void *, const void *)); ``` * test 稱為一個 **designator** 。 * 在規格書有提到:除了當作 sizeof operator 與 & operator 的 operand 之外, designator 會被轉型成一個 "**pointer to function return type**" 。也就是說,上述的 test 會被轉成 function pointer 。 * 而既然是指標,當然可以對其進行提領 (value of) 運算,所以 (*fptr) 會變成 function designator ,但因為其並未進行 sizeof 或 & 運算,最後還是會被轉回 function pointer。也就是說,若一個 function pointer 在前面加上若干個 * 運算,最後還是會變回一個單純的 function pointer 。
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up