close

「學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

arrow
arrow
    全站熱搜

    Edison 發表在 痞客邦 留言(27) 人氣()