「學C語言如果不會用指標,那千萬別說學過」我非常讚同這句話..
對於一般人,指標往往是進入 C 語言後難以跨過的障礙,我也不例外..
這篇主要是在說明指標變數的基本觀念..
1. 指標的宣告與基本使用
假設我今天有一變數宣告成: int a = 10;
而我現在又要再宣告一個指標 ptr 想要儲存變數 a 的位址,有二種宣告方式可以達成。
請記住二點,(a) 我現在要指向的是 "一個整數變數 a" (b) 我的指標是來 存位址值 的
(1.1) 不賦初值的宣告方式
int *ptr;
ptr = &a;
(1.2) 賦予初值的宣告方式
int *ptr = &a;
由於我指向的變數是 int ,所以宣告時是宣告成 int *ptr,如果今天換成 double b; 那麼宣告方式也要換成 double *ptr; 這是指標的宣告。先以(1.1) 為例,其實第一行並不是好的習慣,當你一開始宣告還不知道要指向哪個變數的時候,請記得這麼寫法:
int *ptr = NULL;
先將指標指向 NULL ,之後要用到的時候再抓出來用就可以了。先說一下 &a 代表什麼意思, &a 就是指我程式中, a 所在記憶體的位置。這下總算清楚了吧.. (1.1) 第二行為例:
ptr = &a;
等於是說,我把a 的位址(也就是&a)存到 ptr 中。現在,馬上用圖解說明 (1.1) 的指令..
2. 圖解說明
(2.1) int a = 10;
現在第一步是宣告一個整數變數 a,此時 OS 會為程式配罝一個記憶體位置給變數a,我們假設記憶體配置到的位置是12FF80,同時由於我在宣告時,也設了 a 的初值為 10,所以變數 a 的儲存值即為 10,示意圖如下所示。
|
儲存值 |
…….. |
…….. |
…….. |
…….. |
10 |
….. |
|
記憶體位址 |
…….. |
…….. |
…….. |
…….. |
12FF80 |
12FF81 |
|
|
|
|
|
|
變數a |
|
(2.2) int *ptr;
接著我宣告了一個指向整數的 整數指標變數 ptr,OS會配置一個記憶體位置給 ptr,在這裡也假設他的位址是12FF54。記得,ptr 是用來儲存記憶體位置的。但由於我現在 ptr 並還沒給初值(也就是說我還沒讓 ptr 指向某個變數),所以 ptr 的值現在都還不知道。示意圖如下所示:
|
儲存值 |
?????? |
…….. |
…….. |
…….. |
10 |
….. |
|
記憶體位址 |
12FF54 |
12FF55 |
12FF56 |
…….. |
12FF80 |
12FF81 |
|
|
指標ptr |
|
|
|
變數a |
|
(2.3) ptr = &a;
再來,我將 a 變數的位址值(也就是&a) 給 ptr,所以指標變數 ptr 就存變數 a 的位址。
示意圖如下所示:
|
儲存值 |
12FF80 |
…….. |
…….. |
…….. |
10 |
….. |
|
記憶體位址 |
12FF54 |
12FF55 |
12FF56 |
…….. |
12FF80 |
12FF81 |
|
|
指標ptr |
|
|
|
變數a |
|
當然,如果像是
int a = 10;
int *ptr = &a;
這種宣告直接賦予初值的話,(2.2) 的步驟將會跳過。
3. 如何使用指標取得變數值
請先記得下列二種運算子
(3.1) & : 取址運算子,如我所說的, &a 就是取得 a 的位址,
(3.2) * : (依址取值運算子), 以上面的 (2.3) ptr = &a; 為例,現在 ptr 已經存放了 a 變數的位址,所以
printf("%0X\n", ptr); 是顯示 ptr 的內容值,也就是 12FF80
printf("%0X\n", *ptr); 由於 ptr 是 12FF80,所以跑到位址 12FF80 的地方去抓它的值,故顯示出來就是10
4. 使用指標注意事項
(4.1) 儲存位址的變數一定要是指標:當然有人會想到,既然我只是要存放一個數值,只是這個數值是位址,那為什麼不使用這種方式存放呢?
int a = 0;
int ptr = &a; // complier error
原因很簡單,在 C/C++ 裡面要存變數的位址值,就是要用指標的型態去存
(4.2) 在指標變數還沒確定指向某一變數時,不能取用:指標變數主要的功能是 "依址取值",如果你還沒給他一個明確的位址值(像是 ptr = &a ,這就有給一個明確的位址值了)就進行調用,到時程式執行時,會從怪怪的記憶體位址去抓值出來,(因為你不知道指標裡面放的是什麼),假設指標一開始沒有初始化,所存的值是 0XFFFFFF,又假設 0XFFFFFF 是 OS 裡不可存取的記憶體位址,那麼將會發生不可預期的後果(run time error)
(4.3) 指標不能指向一個常數:如果你已經 #define N 100,那麼指標就不能指向 N。
在了解上述的原理之後,接下來附上一段 source code ,建議最好是準備紙筆畫位址 - 儲存址 的大概對應圖,如果下面的 code 有些部份為什麼 comment 掉不懂的話,請將上面再詳細看幾遍,有好處沒壞處的。程式執行結果不了解了,也歡迎留言與我討論。
5. 程式碼
// ====================================
// FileName: BasicPtr.cpp
// Author : Edison.Shih.
// Complier: VC 2008
#include <stdio.h>
// ====================================
int main(int argc, char **argv)
{
/*
int *ptr1;
printf(" ptr1 = %0X\n", ptr1); // runtime error
printf("&ptr1 = %0X\n", &ptr1); // runtime error
printf("*ptr1 = %0X\n", *ptr1); // runtime error
*/
printf("========================================== \n");
int a = 0X10;
printf(" a = %0X\n", a); // 10
printf(" &a = %0X\n", &a); // the address of a
// printf(" *a = %0X\n", *a); // complier error.
printf("============ int *ptr2 = NULL ============ \n");
int *ptr2 = NULL;
printf(" ptr2 = %0X\n", ptr2); // 0,
printf("&ptr2 = %0X\n", &ptr2); // ptr2 of address, ex:12FF60
// printf("*ptr2 = %0X\n", *ptr2); // logic error, runtime error
printf("================ ptr2 = &a =============== \n");
ptr2 = &a;
printf(" ptr2 = %0X\n", ptr2); // the address of a, =&a
printf("&ptr2 = %0X\n", &ptr2); // ptr2 of address, ex:12FF60
printf("*ptr2 = %0X\n", *ptr2); // the value of a, =10
return 0;
}
// ====================================
6. 執行結果
==========================================
a = 10
&a = 12FF60
============ int *ptr2 = NULL ============
ptr2 = 0
&ptr2 = 12FF54
================ ptr2 = &a ===============
ptr2 = 12FF60
&ptr2 = 12FF54
*ptr2 = 10

int *ptr1; printf("&ptr1=%0X\n", &ptr1); // 應該可以取得到位址吧???
可以。取得 ptr1 這個變數 (向指整數之指標) 本身的位址值。
謝謝板主的回答
*****
大大的講解真是太讚了!!! 比我們計程教授上整節課都清楚!!!
感謝如此精闢的講解,學校教授上的超不清楚的 經過大大完整的解說,一整個豁然開朗阿 ㄏㄏ
很清楚 學校兩小時聽不懂這裡花十分鐘搞懂
感謝 很詳盡
非常謝謝 解惑了
超級感謝~期末考有救了^^
謝謝 還有精闢讀圖解 終於弄懂指標了
請問指標為什麼不能指向常數?? 以下是我實驗,當我印*ptr時會crash,但單純印ptr時會印出aaa,想請問為什麼?? 謝謝。 char *ptr="aaa"; printf("*ptr = %s", *ptr);
printf("ptr = %s" , ptr); printf("ptr = %c" , * ptr); 結果、意義不同。
講得太棒了啦!!!!
有圖解說,非常清楚!
除了讚,還是讚~ 終於懂了
借分享,謝謝!
收穫良多!感謝大大
講得太詳細了! 其他網誌看了幾個小時都看不懂 在這裡不到10分鐘就懂 感謝大大!
不好意思版主 6.執行結果 關於&a位址是怎麼得到呢 程式碼裡面沒有給予位址不是嗎
回#18 當 int a = 0X10; ←宣告這段時,就已經為記憶體分配了一個位址囉! 儲存值 : 0X10 記憶體位址: 12FF60
請問那個%0x到底是什麼啊?
萬般感謝版主的教學,終於明白了~~
感謝分享!說明得很清楚!
感謝教學, 程式沒有疑問, 但是兩個地方註解 // ptr2 of address 是否應寫成 // address of ptr2 比較合乎文法語意呢?
講得太棒了,有圖秒懂,描述又有條理,謝謝您
感謝
原來是這樣 難怪原本1.2那邊我看不懂 學校教科書寫得不好 ˋ我ˋ一直以為ptr就等於是排在記憶體那邊 原來*是先去找到後再去那個記憶體找(不太會表達 反正就是一種認知錯誤) 原本一直卡在覺得為什麼*ptr裡面不是數值怎麼會直接把位置給他 原來是這樣 非常感謝
為甚麼a的位址跟ptr2的位址是差12,不是差4個位元