CHAPTER 10 - epaper.gotop.com.twepaper.gotop.com.tw/pdf/AEL012600.pdf · 10-5 10 chapter...

12
CHAPTER 10 變數的儲存類別 10.1 變數的儲存類別 10.2 自動變數 10.3 靜態變數 10.4 外部變數 10.5 暫存器變數 10.6 習題

Transcript of CHAPTER 10 - epaper.gotop.com.twepaper.gotop.com.tw/pdf/AEL012600.pdf · 10-5 10 chapter...

  • CHAPTER

    10

    變數的儲存類別

    10.1 變數的儲存類別

    10.2 自動變數

    10.3 靜態變數

    10.4 外部變數

    10.5 暫存器變數

    10.6 習題

  • 10-2

    10.1 變數的儲存類別

    在第三章當您宣告一個變數時,便可得知變數的名稱、變數是屬於

    哪種資料型別、該變數佔用記憶體有多少個 Bytes。當設計較大程式時,

    使用的變數一多,就必須考慮變數在記憶體中的配置情形。本章主要探

    討變數的儲存類別 (Storage Class),透過宣告變數的同時可在最前面加上

    儲 存 類 別 關 鍵 字 來 決 定 變 數 在 程 式 中 的 有 效 範 圍 (scope) 、 持 久 性

    (Duration)以及變數在記憶體的儲存位置 (Location)。「有效範圍」就是指

    變數允許使用的範圍是屬於局部或全域範圍。所謂持久性就是生命期

    (Life Time)是指變數開始產生一直到該變數消失的起訖時間。在第 8.4

    節已介紹過,若變數定義在函式的外面,其範圍視為全域 (Global),若定

    義在函式裡面,其範圍視為局部 (Local)。所以,使用儲存類別來控制變

    數的好處不但可提高記憶體的使用率、而且加快程式的執行速度及減少

    變數誤用。至於 C 語言所提供變數的儲存類別有下列四種關鍵字:

    1. auto:宣告自動變數(Automatic Variable)或稱內部變數

    2. static:宣告靜態變數(Static Variable)

    3. extern:宣告外部變數(External Variable)

    4. register:宣告暫存器變數(Register Variable)

    10.2 自動變數

    自動變數 (automatic Variables)又稱為內部變數,一般在函式內宣告

    的變數若未註明儲存類別,都預設為自動變數。譬如:在第八章中函式

    內宣告的局部變數以及區塊內所宣告的區域變數都是屬於自動變數。自

    動變數在程式執行階段 (Run Time),系統才在動態堆疊區配置記憶體給

    該變數使用,當函式完成它的工作離開函式返回呼叫處,該變數又從堆

    疊中取出釋放掉,將使用過的記憶體歸還給系統。所以,自動變數就是

    能自動產生與自動消失的變數。

  • 變數的儲存類別

    10-3

    10 CHAPTER

    當宣告一個變數時,只要在資料型別的前面加上 auto 關鍵字就變成

    一個自動變數。當您宣告一個變數的同時,若在資料型別前面未加上任

    何儲存類別關鍵字即預設為自動變數。因此,像在函式內所宣告的局部

    變數,若沒有指定儲存類別,預設為自動變數。自動變數的有效範圍是

    由函式內變數的宣告處開始,一直到離開函式時,自動變數將釋放掉所

    佔用的記憶體空間,等到下次進入函式時,再重新配置記憶體位址給該

    變數使用,而無法保留其舊值。至於自動變數的宣告方式如下:

    auto int score;

    10.3 靜態變數

    由於自動變數是屬於局部變數,因此一旦離開函式或程式區塊 (以大

    括號括住 ),該變數便不存在,下次進入時再重新配置記憶體並給予初

    值。但是在設計程式時,可能需要在自動變數離開其有效範圍時,希望

    能夠保留其值,待下次進入該有效範圍時能夠再繼續使用先前保留的舊

    值。此時就需要將此種變數設成「靜態變數」 (static variables)。靜態變

    數可分為「局部靜態變數」和「全域靜態變數」,此兩種變數的寫法都如

    下面敘述在宣告變數的同時,於資料型別前面加上 static 關鍵字。

    static int score;

    局部靜態變數和全域靜態變數的說明如下:

    一. 局部靜態變數

    就是將變數宣告在函式內或是複合式區塊內,此種變數的有效範圍

    和自動變數一樣,只不過是局部靜態變數離開有效範圍時會保留其值,

    下次再進入該有效範圍時,繼續延用保留的值,其它函式是無法使用到

    該變數,是屬於局部變數的一種,但生命期一直到程式結束為止,這是

    和自動變數不一樣的地方。此種變數在程式編譯階段 (Compiling Time)

    時,馬上會配置一個固定的記憶體給該變數使用,而不是像自動變數在

  • 10-4

    執行階段 (Running Time)才動態配置記憶體。因此,在程式尚未結束前仍

    佔用該記憶體,如此該變數離開該有效範圍時,方可保留其值不會消失,

    一直到程式結束才會將用過記憶體歸還給系統。譬如下面 local_static.c

    範例:在 fun1()函式內 a_var1 變數為自動變數、l_stat 局部靜態變數,本

    程式第一次呼叫 fun1()函式時將這兩個變數的初值都設成 10,程式中共

    呼叫 fun1()函式五次,每次都會顯示 a_var 和 l_stat 變數值後再將其值分

    別加 1,結果 a_var 自動變數每次進入函式時其值都被重新設定成 10,

    所以呼叫函式五次顯示其值仍為 10。但是 l_stat 局部靜態變數每次其值

    顯示完畢加 1 後再離開 fun1() 函式時均能將值保留到下次進入時使用,

    結果呼叫函式五次,其值分別為 10~14。由於在 main()函式的 for 迴圈

    中有參用到 times 變數,而且在 fun1()函式亦參用到,因此必須將 times

    設成全域變數,其範圍為整個程式有效。

    FileName : local_static.c 01 #include

    02 #include

    03 void fun1();

    04 int times=1; /* 全域變數 */

    05

    06 int main(int argc, char *argv[])

    07 {

    08 for (times=1 ; times

  • 變數的儲存類別

    10-5

    10 CHAPTER

    執行結果

    二. 全域靜態變數

    全域靜態變數是將變數宣告在函式之外,其使用時機就是當一個檔

    案中的全域變數不希望被其他的檔案參用到時,可將此變數宣告為「外

    部靜態」,亦稱為「全域靜態變數」,其持久性和有效範圍和全域變數一

    樣。外部靜態變數的生命週期是由該變數宣告開始,便在記憶體內佔用

    一個位置來存放該變數的內容,一直到程式結束執行為止,其有效範圍

    整個程式內均有效。也就是說此類變數在同一個程式檔中所有函式內皆

    可參用,其他程式檔便無法存取。由上可知局部靜態變數和全域靜態變

    數的持久性都是到程式執行結束為止。譬如下例假設左右兩個彼此是獨

    立的兩個檔案,將兩個檔案編譯在一起時, times 是屬於全域變數,它允

    許 file1.c 檔的 main()、 fun1()和 file2.c 檔的 fun2()、 fun3()共同參用。至

    於 g_stat 為全域靜態變數,它僅限 file1.c 檔的 main()、fun1()共同參用。

  • 10-6

    f i le1.c f i le2.c

    10.4 外部變數

    外部變數 (External Variable)是屬於全域變數,其使用時機是當一個

    檔案需要參用的變數不是放在自己的程式檔中而是放在另一個程式檔

    中。所以其有效範圍跨越原程式,允許別的程式也能參用到該變數。譬

    如:下圖中 file2.c 檔欲參用到 file1.c 檔的 a1 整數變數,其宣告方式即

    如下圖在 file1.c 檔所有函式外面,先宣告 a1 為全域變數 (int a1),接著

    在 file2.c 檔所有函式外面宣告 a1 為外部變數 (extern int a1),兩者的變數

    宣告必須在所有函式外面:

    file1.c

    int a1;

    int main(int argc, char *argv[])

    {

    ……

    return 0;

    }

    file2.c

    extern int a1;

    int main(int argc, char *argv[])

    {

    ……

    return 0;

    }

    int times; static g_stat; main() { }

    fun1(){

    }

    fun2() { }

    fun3(){

    }

  • 變數的儲存類別

    10-7

    10 CHAPTER

    由上圖可知,外部變數的有效範圍,是由該變數宣告處開始一直到

    程式結束。若將 file1.c 檔的 int a1; 前面加上 static 關鍵字變成外部靜態

    變數,a1 的有效範圍就僅限於 file1.c 檔,file2.c 檔便無法參用到該變數。

    若外部變數未宣告之前,程式中的函式想要參用到原程式檔中外面

    的變數,必須在該函式內使用 extern …; 來宣告欲參用的變數是在外

    部。譬如下例 extern1.c 範例中的 int i; 為全域變數,i 變數卻宣告在 main()

    及 fun1()後面,由於比較慢宣告,而 main()及 fun1()函式中便需要參用到

    此變數 i,因此,必須在 main()及 fun1()函式中參用到 i 之前先宣告 extern

    int i; 如此 main()、 fun1()、 fun2()便可參用到全域變數 i。

    FileName : extern1.c 01 #include

    02 #include

    03 void fun1();

    04 void fun2();

    05

    06 int main(int argc, char *argv[])

    07 {

    08 extern int i; /* 宣告外部變數 */

    09 printf("==> in main() i=%d\n",i++);

    10 fun1();

    11 fun2();

    12 system("PAUSE");

    13 return 0;

    14 }

    15 void fun1()

    16 {

    17 extern int i; /* 宣告外部變數 */

    18 printf("==> in fun1() i=%d\n",i++);

    19 }

    20

    21 int i=10; /* 宣告全域變數 */

    22

    23 void fun2()

    24 {

    25 printf("==> in fun2() i=%d\n",i);

    26 }

  • 10-8

    :extern_var.dsw

    使用 total 外部變數用來記錄購物的目前應付總金額,當使用者輸入購物金額時會累計到 total 變數中。每一次輸入金額後即會顯示目前的應付總金額,以及詢問是否繼續購物,若按 'y' 或 'Y' 鍵即繼續購物,按其他鍵則結束程式的執行。

    執行結果

    問題分析

    1. 本例共使用兩個程式檔。分別為 shopping.h 自訂標頭檔;extern_var.c為主程式。shopping.h 標頭檔內宣告了 total 全域變數,以及定義了累加購物金額的 buy()函式。

    2. extern_var.c 程式檔要使用 shopping.h 的 total 變數,可以使用 extern來宣告 total 變數,以達成跨檔案取用變數的目的。

    FileName : shopping.h 01 int total; /*全域變數*/ 02 int buy(int); 03 int buy(int a) 04 { 05 return total+=a; 06 }

  • 變數的儲存類別

    10-9

    10 CHAPTER

    FileName : extern_var.c

    01 #include

    02 #include

    03 #include

    04 #include

    05 #include "shopping.h" /*含入 shopping.h標頭檔*/

    06

    07 int main(int argc, char *argv[])

    08 {

    09 extern int total; /*使用 shopping.h的 total全域變數*/

    10 char ch;

    11 int keyin;

    12 do

    13 {

    14 printf(" 請輸入購物金額:");

    15 scanf("%d", &keyin);

    16 printf(" 目前應付總金額:%d\n", buy(keyin));

    17 printf("是否(y/n)繼續購物:");

    18 ch=toupper(getche());

    19 printf("\n\n");

    20 }while(ch=='Y');

    21 printf("謝謝您的購買,總共 %d 元\n", total);

    22 system("PAUSE");

    23 return 0;

    24 }

    說明

    1. 第 9 行:使用 extern 宣告 total 變數,使 extern_var.c 可以使用 shopping.h

    的 total 變數,以達成跨檔案存取變數的目的。

    10.5 暫存器變數

    自動變數和暫存器變數的生命週期和有效範圍相同,兩者不一樣的

    地方在於自動變數是存放在記憶體中,而暫存器變數是直接存放在 CPU

  • 10-10

    裡的暫存器中。因為暫存器變數是直接存放於暫存器內,當做變數運算

    時,不需要將記憶體的變數值拷貝到暫存器內,因此暫存器變數存取速

    度當然比自動變數還要快,所以,使用暫存器變數可提高運算的速度。

    以下是暫存器變數宣告的寫法:

    register int i; /* 宣告暫存器變數 i */

    下表列出各類變數的差異:

    儲存類別 關鍵字 宣告位置 持久性(Duration) 有效範圍(scope)

    自動變數 auto 函式內或區塊內 暫時 區域 Local

    暫存器變數 register 函式內或區塊內 暫時 區域 Local

    靜態變數 static 函式內或區塊內 persistence 區域 Local

    外部變數 extern 函式外面 persistence Global(所有檔案)

    外部靜態 static 函式外面 persistence Global(一個檔案)

    10.6 習題

    一. 選擇題

    1. 如果跨檔案要使用外部變數,您可以使用什麼關鍵字來宣告外部變數?

    (1) static (2) extern (3) global (4) auto

    2. 自動變數其實就是?

    (1) 靜態變數 (2) 外部變數 (3) 區域變數 (4) 暫存器變數

    3. 自動變數的有效範圍是?

    (1) 變數所宣告的區塊範例

    (2) 整份程式檔

  • 變數的儲存類別

    10-11

    10 CHAPTER

    4. 全域變數的生命期是?

    (1) 離開函式後即將變數所佔用的記憶體釋放掉

    (2) 程式檔執行結束才釋放變數所佔用的記憶體

    5. 如下程式,在 main()函式內若要使用宣告在 fun()函式之前的外部變數

    i,則在 main()函式內應如何宣告 i 變數。

    int main(int argc, char *argv[])

    {

    /* 此處應如何宣告才能使用 i 變數 */

    ……

    }

    int i;

    funA()

    {

    }

    (1) static int i; (2) auto int i; (3) register int i; (4) extern int i;

    6. 靜態變數可分為?(複選)

    (1) 局部靜態變數 (2) 全域靜態變數

    (3) 自動靜態變數 (4) 暫存區靜態變數

    7. 請問暫存器變數的宣告位置可以在何處?

    (1) 函式內 (2) 程式區塊內

    (3) 函式外面 (4) 函式內或程式區塊內

    8. 宣告自動變數必須在資料型別之前加上?

    (1) static (2) extern (3) global (4) auto

    9. 如果宣告靜態變數,您可以使用什麼關鍵字來宣告變數?

    (1) static (2) extern (3) shard (4) public

    10. 若 b.c 程式檔要使用 a.c 程式檔的 a1 變數,則 b.c 程式檔的 [註 1] 處應

    如何撰寫?

    (1) static int a1; (2) auto int a1;

    (3) register int a1; (4) extern int a1;

  • 10-12

    a.c

    int a1;

    int main(void)

    {

    ……

    return 0;

    }

    b.c

    [註 1]

    int main(void)

    {

    ……

    return 0;

    }

    二. 問答題

    1. 試簡述全域變數與區域變數的差異。

    2. 試簡述全域靜態變數與局部靜態變數的差異。

    3. 何謂暫存器變數?

    4. 試列出自動變數,暫存器變數,靜態變數,外部變數及外部靜態變數

    所宣告位置的持久性及有效範圍。

    5. 試寫出 C 語言所提供變數的各種儲存類別所使用的關鍵字。並簡述各

    種變數儲存類別的功能。

    三. 程式設計

    1. 定義一個 rndfile.h 標頭檔,並在該檔案內撰寫可以呼叫四星彩及樂透

    彩開獎號碼的函式。

    2. 在兩個標頭檔內分別撰寫二分搜尋法及循序搜尋法的函式,然後根據

    主程式巨集 ID 的值來撰擇要含入二分搜尋法或循序搜尋法函式的哪

    一個標頭檔。