C語言 - 第十七章 | 指標 - 指標與記憶體位址
什麼是指標?
指標(Pointer
),指標可指向一個記憶體位址,可對物件作間接操作,指標擁有型態,這用來告訴編譯器如何解釋記憶體空間的內容,以及每一次運算的大小。
什麼是變數?
變數(Variable
)提供具名稱的記憶體儲存空間,一個變數關聯一個資料型態、儲存的值與儲存空間的位址值。
變數的資料型態決定了變數分配到的記憶體大小;變數本身的值是指儲存於記憶體中的某個數值,可以透過變數名稱取得這個數值,這個數值又稱為rvalue
或read value
;而變數的位址值則是指變數所分配到的記憶體之位置,變數本身又稱為lvalue
或 location value
。
如果想知道變數的記憶體位址為何,可以使用&
運算子,&
是取址運算子(Address-of operator
),可以取出變數的記憶體位址。
1 |
|
宣告了一個int
整數變數var
,var
指向的記憶體位址是0x002DFA50
,這是記憶體位址的16
進位表示法,從0x002DFA50
後的4
個位元組都是var
所配置到的記憶體空間,現在這個空間中儲存值為10
。
註:每次運行宣告的整數變數所配置的記憶體位址,都是不一樣的。
指標
type
存取變數即直接對所分配到的記憶體空間作存取,指標(Pointer
)則提供了間接性,指標可指向特定的記憶體位址,而不直接操作變數或物件,宣告一個指標如下:
1 | type *ptr; |
type
是指標的型態,每一個指標都有一個相對應的型態,用以指出所指向的資料或物件之型態有所不同,編譯器根據指標型態來確定特定記憶體位址上的資料如何解釋,以及如何進行指標運算(Pointer arithmetic
),幾個指標宣告的範例:
1 | int *iptr; |
可以使用&
運算子取出變數的位址值並指定給指標,例如:
1 |
|
你使用&
來取出變數var
指向的記憶體位址,然後將這個位址指定給指標ptr
,因此ptr
儲存的值就與&var
取出的值相同。
指標擁有兩種操作特性,一是操作指標所儲存的位址,一是操作指標所指向位址之資料,可以使用提取(Dereference
)運算子*
來提取指標指向位址的資料,例如:
1 |
|
如果已經取得了記憶體位置,當將某個值指定給*ptr
時,該記憶體位置的值也會跟著改變,相當於告訴程式,將值放到ptr
指向的記憶體位址,例如:
1 |
|
當指標ptr
儲存的值與變數var
指向的記憶體位置相同時,當對*ptr
進行指定的動作時,就會將值直接存入該記憶體位置,因此再透過變數var
取出的值也就改變了。
如果宣告指標但不指定初值,則指標指向的位址是未知的,存取未知位址的記憶體內容是危險的,例如:
1 | int *ptr; |
這個程式片段並未初始指標就指定值給*ptr
,所以會造成不可預知的結果(通常是記憶體區段錯誤),最好為指標設定初值,如果指標一開始不指向任何的位址,則可設定初值為0
,表示不指向任何位址,例如:
1 | int *iptr = 0; |
在這邊必須注意一個指標宣告常犯的錯誤,在指標宣告時,可以靠在名稱旁邊,也可以靠在關鍵字旁邊,例如:
1 | int *ptr1; |
這兩個宣告方式都是可允許的,一般比較傾向用第一個,因為可以避免以下的錯誤:
1 | // 這樣的宣告方式,初學者可能以為ptr2也是指標,但事實上並不是。 |
void
有時候,只希望儲存記憶體的位址,然後將之與另一個記憶體位址作比較,這時並不需要關心型態的問題,可以使用void*
來宣告指標,例如:
1 | void *ptr; |
由於void
型態的指標沒有任何的型態資訊,所以只用來持有位址資訊,不可以使用*
運算子對void
型態指標提取值,而必須作轉型動作至對應的型態,例如:
1 |
|
const
const
宣告的變數,被const
宣告的變數一但被指定值,就不能再改變變數的值。
1 | const int var = 10; |
1 | int x = 10; |
註:以上參考了
hackersir gitbooks
指標與記憶體位址